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>
16 #include "lib/rpmfi_internal.h"
17 #include "lib/rpmte_internal.h" /* relocations */
18 #include "lib/cpio.h" /* XXX CPIO_FOO */
19 #include "lib/fsm.h" /* rpmpsm stuff for now */
20 #include "lib/rpmug.h"
21 #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
30 typedef struct hardlinks_s * hardlinks_t;
35 #define HASHTYPE nlinkHash
37 #define HTDATATYPE struct hardlinks_s *
38 #include "lib/rpmhash.H"
39 #include "lib/rpmhash.C"
44 typedef int (*iterfunc)(rpmfi fi);
47 int i; /*!< Current file index. */
48 int j; /*!< Current directory index. */
49 iterfunc next; /*!< Iterator function. */
50 char * fn; /*!< File name buffer. */
51 char * ofn; /*!< Original file name buffer. */
53 int intervalStart; /*!< Start of iterating interval. */
54 int intervalEnd; /*!< End of iterating interval. */
56 rpmfiles files; /*!< File info set */
57 rpmcpio_t archive; /*!< Archive with payload */
58 unsigned char * found; /*!< Bit field of files found in the archive */
59 int nrefs; /*!< Reference count */
63 rpm_count_t dc; /*!< No. of directories. */
64 rpm_count_t fc; /*!< No. of files. */
66 rpmsid * bnid; /*!< Index to base name(s) (pool) */
67 rpmsid * dnid; /*!< Index to directory name(s) (pool) */
68 uint32_t * dil; /*!< Directory indice(s) (from header) */
71 typedef struct rpmfn_s * rpmfn;
74 * A package filename set.
77 Header h; /*!< Header for file info set (or NULL) */
78 rpmstrPool pool; /*!< String pool of this file info set */
80 struct rpmfn_s fndata; /*!< File name data */
81 struct rpmfn_s *ofndata; /*!< Original file name data */
83 rpmsid * flinks; /*!< Index to file link(s) (pool) */
85 rpm_flag_t * fflags; /*!< File flag(s) (from header) */
86 rpm_off_t * fsizes; /*!< File size(s) (from header) */
87 rpm_loff_t * lfsizes; /*!< File size(s) (from header) */
88 rpm_time_t * fmtimes; /*!< File modification time(s) (from header) */
89 rpm_mode_t * fmodes; /*!< File mode(s) (from header) */
90 rpm_rdev_t * frdevs; /*!< File rdev(s) (from header) */
91 rpm_ino_t * finodes; /*!< File inodes(s) (from header) */
93 rpmsid * fuser; /*!< Index to file owner(s) (misc pool) */
94 rpmsid * fgroup; /*!< Index to file group(s) (misc pool) */
95 rpmsid * flangs; /*!< Index to file lang(s) (misc pool) */
97 char * fstates; /*!< File state(s) (from header) */
99 rpm_color_t * fcolors; /*!< File color bits (header) */
100 char ** fcaps; /*!< File capability strings (header) */
102 char ** cdict; /*!< File class dictionary (header) */
103 rpm_count_t ncdict; /*!< No. of class entries. */
104 uint32_t * fcdictx; /*!< File class dictionary index (header) */
106 uint32_t * ddict; /*!< File depends dictionary (header) */
107 rpm_count_t nddict; /*!< No. of depends entries. */
108 uint32_t * fddictx; /*!< File depends dictionary start (header) */
109 uint32_t * fddictn; /*!< File depends dictionary count (header) */
110 rpm_flag_t * vflags; /*!< File verify flag(s) (from header) */
112 rpmfiFlags fiflags; /*!< file info set control flags */
114 struct fingerPrint_s * fps; /*!< File fingerprint(s). */
116 int digestalgo; /*!< File digest algorithm */
117 int signaturelength; /*!< File signature length */
118 unsigned char * digests; /*!< File digests in binary. */
119 unsigned char * signatures; /*!< File signatures in binary. */
121 struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */
122 rpm_off_t * replacedSizes; /*!< (TR_ADDED) */
123 rpm_loff_t * replacedLSizes;/*!< (TR_ADDED) */
125 int nrefs; /*!< Reference count. */
128 static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd);
129 static int cmpPoolFn(rpmstrPool pool, rpmfn files, int ix, const char * fn);
131 static rpmfiles rpmfilesUnlink(rpmfiles fi)
138 rpmfiles rpmfilesLink(rpmfiles fi)
145 static rpmfi rpmfiUnlink(rpmfi fi)
152 rpmfi rpmfiLink(rpmfi fi)
160 * Collect and validate file path data from header.
161 * Return the number of files found (could be none) or -1 on error.
163 static int rpmfnInit(rpmfn fndata, rpmTagVal bntag, Header h, rpmstrPool pool)
165 struct rpmtd_s bn, dn, dx;
166 rpmTagVal dntag, ditag;
169 if (bntag == RPMTAG_BASENAMES) {
170 dntag = RPMTAG_DIRNAMES;
171 ditag = RPMTAG_DIRINDEXES;
172 } else if (bntag == RPMTAG_ORIGBASENAMES) {
173 dntag = RPMTAG_ORIGDIRNAMES;
174 ditag = RPMTAG_ORIGDIRINDEXES;
179 /* Grab and validate file triplet data (if there is any) */
180 if (headerGet(h, bntag, &bn, HEADERGET_MINMEM)) {
181 headerGet(h, dntag, &dn, HEADERGET_MINMEM);
182 headerGet(h, ditag, &dx, HEADERGET_ALLOC);
184 if (indexSane(&bn, &dn, &dx)) {
185 /* Init the file triplet data */
186 fndata->fc = rpmtdCount(&bn);
187 fndata->dc = rpmtdCount(&dn);
188 fndata->bnid = rpmtdToPool(&bn, pool);
189 fndata->dnid = rpmtdToPool(&dn, pool);
190 /* Steal index data from the td (pooh...) */
191 fndata->dil = dx.data;
195 memset(fndata, 0, sizeof(*fndata));
206 static void rpmfnClear(rpmfn fndata)
212 memset(fndata, 0, sizeof(*fndata));
216 static rpm_count_t rpmfnFC(rpmfn fndata)
218 return (fndata != NULL) ? fndata->fc :0;
221 static rpm_count_t rpmfnDC(rpmfn fndata)
223 return (fndata != NULL) ? fndata->dc : 0;
226 static int rpmfnDI(rpmfn fndata, int ix)
229 if (ix >= 0 && ix < rpmfnFC(fndata)) {
230 if (fndata->dil != NULL)
236 static rpmsid rpmfnBNId(rpmfn fndata, int ix)
239 if (ix >= 0 && ix < rpmfnFC(fndata)) {
240 if (fndata->bnid != NULL)
241 id = fndata->bnid[ix];
246 static rpmsid rpmfnDNId(rpmfn fndata, int ix)
249 if (ix >= 0 && ix < rpmfnDC(fndata)) {
250 if (fndata->dnid != NULL)
251 id = fndata->dnid[ix];
256 static const char * rpmfnBN(rpmstrPool pool, rpmfn fndata, int ix)
258 return rpmstrPoolStr(pool, rpmfnBNId(fndata, ix));
261 static const char * rpmfnDN(rpmstrPool pool, rpmfn fndata, int ix)
263 return rpmstrPoolStr(pool, rpmfnDNId(fndata, ix));
266 static char * rpmfnFN(rpmstrPool pool, rpmfn fndata, int ix)
269 if (ix >= 0 && ix < rpmfnFC(fndata)) {
270 fn = rstrscat(NULL, rpmfnDN(pool, fndata, rpmfnDI(fndata, ix)),
271 rpmfnBN(pool, fndata, ix), NULL);
276 rpm_count_t rpmfilesFC(rpmfiles fi)
278 return (fi != NULL ? rpmfnFC(&fi->fndata) : 0);
281 rpm_count_t rpmfilesDC(rpmfiles fi)
283 return (fi != NULL ? rpmfnDC(&fi->fndata) : 0);
286 int rpmfilesDigestAlgo(rpmfiles fi)
288 return (fi != NULL) ? fi->digestalgo : 0;
291 rpm_count_t rpmfiFC(rpmfi fi)
293 return (fi != NULL ? rpmfilesFC(fi->files) : 0);
296 rpm_count_t rpmfiDC(rpmfi fi)
298 return (fi != NULL ? rpmfilesDC(fi->files) : 0);
302 int rpmfiDI(rpmfi fi)
307 int rpmfiFX(rpmfi fi)
309 return (fi != NULL ? fi->i : -1);
312 int rpmfiSetFX(rpmfi fi, int fx)
316 if (fi != NULL && fx >= 0 && fx < rpmfilesFC(fi->files)) {
319 fi->j = rpmfilesDI(fi->files, fi->i);
324 int rpmfiDX(rpmfi fi)
326 return (fi != NULL ? fi->j : -1);
329 int rpmfiSetDX(rpmfi fi, int dx)
333 if (fi != NULL && dx >= 0 && dx < rpmfiDC(fi)) {
340 int rpmfilesDI(rpmfiles fi, int ix)
342 return (fi != NULL) ? rpmfnDI(&fi->fndata, ix) : -1;
345 int rpmfilesODI(rpmfiles fi, int ix)
347 return (fi != NULL) ? rpmfnDI(fi->ofndata, ix) : -1;
350 rpmsid rpmfilesBNId(rpmfiles fi, int ix)
352 return (fi != NULL) ? rpmfnBNId(&fi->fndata, ix) : 0;
355 rpmsid rpmfilesOBNId(rpmfiles fi, int ix)
357 return (fi != NULL) ? rpmfnBNId(fi->ofndata, ix) : 0;
360 rpmsid rpmfilesDNId(rpmfiles fi, int jx)
362 return (fi != NULL) ? rpmfnDNId(&fi->fndata, jx) : 0;
365 rpmsid rpmfilesODNId(rpmfiles fi, int jx)
367 return (fi != NULL) ? rpmfnDNId(fi->ofndata, jx) : 0;
370 const char * rpmfilesBN(rpmfiles fi, int ix)
372 return (fi != NULL) ? rpmfnBN(fi->pool, &fi->fndata, ix) : NULL;
375 const char * rpmfilesOBN(rpmfiles fi, int ix)
377 return (fi != NULL) ? rpmstrPoolStr(fi->pool, rpmfilesOBNId(fi, ix)) : NULL;
380 const char * rpmfilesDN(rpmfiles fi, int jx)
382 return (fi != NULL) ? rpmfnDN(fi->pool, &fi->fndata, jx) : NULL;
385 const char * rpmfilesODN(rpmfiles fi, int jx)
387 return (fi != NULL) ? rpmstrPoolStr(fi->pool, rpmfilesODNId(fi, jx)) : NULL;
390 char * rpmfilesFN(rpmfiles fi, int ix)
392 return (fi != NULL) ? rpmfnFN(fi->pool, &fi->fndata, ix) : NULL;
395 char * rpmfilesOFN(rpmfiles fi, int ix)
397 return (fi != NULL) ? rpmfnFN(fi->pool, fi->ofndata, ix) : NULL;
400 /* Fn is expected to be relative path, convert directory to relative too */
401 static int cmpPoolFn(rpmstrPool pool, rpmfn files, int ix, const char * fn)
403 rpmsid dnid = rpmfnDNId(files, rpmfnDI(files, ix));
404 const char *dn = rpmstrPoolStr(pool, dnid);
405 const char *reldn = (dn[0] == '/') ? dn + 1 : dn;
406 size_t l = strlen(reldn);
407 int cmp = strncmp(reldn, fn, l);
409 cmp = strcmp(rpmfnBN(pool, files, ix), fn + l);
413 static int rpmfnFindFN(rpmstrPool pool, rpmfn files, const char * fn)
415 int fc = rpmfnFC(files);
418 * Skip payload prefix, turn absolute paths into relative. This
419 * allows handling binary rpm payloads with and without ./ prefix and
420 * srpm payloads which only contain basenames.
422 if (fn[0] == '.' && fn[1] == '/')
427 /* try binary search */
434 mid = (hi + lo) / 2 ;
435 cmp = cmpPoolFn(pool, files, mid, fn);
438 } else if (cmp > 0) {
445 /* not found: try linear search */
446 for (int i=0; i < fc; i++) {
447 if (cmpPoolFn(pool, files, i, fn) == 0)
453 int rpmfilesFindFN(rpmfiles files, const char * fn)
455 return (files && fn) ? rpmfnFindFN(files->pool, &files->fndata, fn) : -1;
458 int rpmfilesFindOFN(rpmfiles files, const char * fn)
460 return (files && fn) ? rpmfnFindFN(files->pool, files->ofndata, fn) : -1;
463 int rpmfiFindFN(rpmfi fi, const char * fn)
468 ix = rpmfilesFindFN(fi->files, fn);
473 int rpmfiFindOFN(rpmfi fi, const char * fn)
478 ix = rpmfilesFindOFN(fi->files, fn);
484 * Dirnames are not sorted when separated from basenames, we need to assemble
485 * the whole path for search (binary or otherwise) purposes.
487 static int cmpPfx(rpmfiles files, int ix, const char *pfx, size_t plen)
489 char *fn = rpmfilesFN(files, ix);
490 int rc = strncmp(pfx, fn, plen);
495 rpmfileAttrs rpmfilesFFlags(rpmfiles fi, int ix)
497 rpmfileAttrs FFlags = 0;
499 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
500 if (fi->fflags != NULL)
501 FFlags = fi->fflags[ix];
506 rpmVerifyAttrs rpmfilesVFlags(rpmfiles fi, int ix)
508 rpmVerifyAttrs VFlags = 0;
510 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
511 if (fi->vflags != NULL)
512 VFlags = fi->vflags[ix];
517 rpm_mode_t rpmfilesFMode(rpmfiles fi, int ix)
519 rpm_mode_t fmode = 0;
521 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
522 if (fi->fmodes != NULL)
523 fmode = fi->fmodes[ix];
528 rpmfileState rpmfilesFState(rpmfiles fi, int ix)
530 rpmfileState fstate = RPMFILE_STATE_MISSING;
532 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
533 if (fi->fstates != NULL)
534 fstate = fi->fstates[ix];
539 int rpmfiDigestAlgo(rpmfi fi)
541 return fi ? rpmfilesDigestAlgo(fi->files) : 0;
544 const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *len)
546 const unsigned char *digest = NULL;
548 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
549 size_t diglen = rpmDigestLength(fi->digestalgo);
550 if (fi->digests != NULL)
551 digest = fi->digests + (diglen * ix);
555 *algo = fi->digestalgo;
560 char * rpmfiFDigestHex(rpmfi fi, int *algo)
563 char *fdigest = NULL;
564 const unsigned char *digest = rpmfiFDigest(fi, algo, &diglen);
566 fdigest = pgpHexStr(digest, diglen);
571 const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
573 const unsigned char *signature = NULL;
575 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
576 if (fi->signatures != NULL)
577 signature = fi->signatures + (fi->signaturelength * ix);
579 *len = fi->signaturelength;
584 const char * rpmfilesFLink(rpmfiles fi, int ix)
586 const char * flink = NULL;
588 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
589 if (fi->flinks != NULL)
590 flink = rpmstrPoolStr(fi->pool, fi->flinks[ix]);
595 rpm_loff_t rpmfilesFSize(rpmfiles fi, int ix)
597 rpm_loff_t fsize = 0;
599 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
600 if (fi->fsizes != NULL)
601 fsize = fi->fsizes[ix];
602 else if (fi->lfsizes != NULL)
603 fsize = fi->lfsizes[ix];
608 rpm_rdev_t rpmfilesFRdev(rpmfiles fi, int ix)
610 rpm_rdev_t frdev = 0;
612 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
613 if (fi->frdevs != NULL)
614 frdev = fi->frdevs[ix];
619 rpm_ino_t rpmfilesFInode(rpmfiles fi, int ix)
621 rpm_ino_t finode = 0;
623 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
624 if (fi->finodes != NULL)
625 finode = fi->finodes[ix];
630 rpm_color_t rpmfilesColor(rpmfiles files)
632 rpm_color_t color = 0;
634 if (files != NULL && files->fcolors != NULL) {
635 int fc = rpmfilesFC(files);
636 for (int i = 0; i < fc; i++)
637 color |= files->fcolors[i];
638 /* XXX ignore all but lsnibble for now. */
644 rpm_color_t rpmfiColor(rpmfi fi)
646 return (fi != NULL) ? rpmfilesColor(fi->files) : 0;
649 rpm_color_t rpmfilesFColor(rpmfiles fi, int ix)
651 rpm_color_t fcolor = 0;
653 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
654 if (fi->fcolors != NULL)
655 /* XXX ignore all but lsnibble for now. */
656 fcolor = (fi->fcolors[ix] & 0x0f);
661 const char * rpmfilesFClass(rpmfiles fi, int ix)
663 const char * fclass = NULL;
666 if (fi != NULL && fi->fcdictx != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
667 cdictx = fi->fcdictx[ix];
668 if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
669 fclass = fi->cdict[cdictx];
674 uint32_t rpmfilesFDepends(rpmfiles fi, int ix, const uint32_t ** fddictp)
678 const uint32_t * fddict = NULL;
680 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
681 if (fi->fddictn != NULL)
682 fddictn = fi->fddictn[ix];
683 if (fddictn > 0 && fi->fddictx != NULL)
684 fddictx = fi->fddictx[ix];
685 if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
686 fddict = fi->ddict + fddictx;
693 uint32_t rpmfilesFLinks(rpmfiles fi, int ix, const int ** files)
697 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
700 struct hardlinks_s ** hardlinks = NULL;
701 nlinkHashGetEntry(fi->nlinks, ix, &hardlinks, NULL, NULL);
703 nlink = hardlinks[0]->nlink;
705 *files = hardlinks[0]->files;
715 uint32_t rpmfiFLinks(rpmfi fi, const int ** files)
717 return rpmfilesFLinks(fi->files, fi ? fi->i : -1, files);
720 uint32_t rpmfilesFNlink(rpmfiles fi, int ix)
722 return rpmfilesFLinks(fi, ix, NULL);
725 rpm_time_t rpmfilesFMtime(rpmfiles fi, int ix)
727 rpm_time_t fmtime = 0;
729 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
730 if (fi->fmtimes != NULL)
731 fmtime = fi->fmtimes[ix];
736 const char * rpmfilesFUser(rpmfiles fi, int ix)
738 const char * fuser = NULL;
740 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
741 if (fi->fuser != NULL)
742 fuser = rpmstrPoolStr(fi->pool, fi->fuser[ix]);
747 const char * rpmfilesFGroup(rpmfiles fi, int ix)
749 const char * fgroup = NULL;
751 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
752 if (fi->fgroup != NULL)
753 fgroup = rpmstrPoolStr(fi->pool, fi->fgroup[ix]);
758 const char * rpmfilesFCaps(rpmfiles fi, int ix)
760 const char *fcaps = NULL;
761 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
762 fcaps = fi->fcaps ? fi->fcaps[ix] : "";
767 const char * rpmfilesFLangs(rpmfiles fi, int ix)
769 const char *flangs = NULL;
770 if (fi != NULL && fi->flangs != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
771 flangs = rpmstrPoolStr(fi->pool, fi->flangs[ix]);
776 int rpmfilesStat(rpmfiles fi, int ix, int flags, struct stat *sb)
780 /* XXX FIXME define proper flags with sane semantics... */
781 int warn = flags & 0x1;
782 const char *user = rpmfilesFUser(fi, ix);
783 const char *group = rpmfilesFGroup(fi, ix);
784 const int * hardlinks = NULL;
785 uint32_t nlinks = rpmfilesFLinks(fi, ix, &hardlinks);
787 memset(sb, 0, sizeof(*sb));
788 sb->st_nlink = nlinks;
789 sb->st_ino = rpmfilesFInode(fi, ix);
790 sb->st_rdev = rpmfilesFRdev(fi, ix);
791 sb->st_mode = rpmfilesFMode(fi, ix);
792 sb->st_mtime = rpmfilesFMtime(fi, ix);
794 /* Only regular files and symlinks have a size */
795 if (S_ISREG(sb->st_mode)) {
796 /* Content and thus size comes with last hardlink */
797 if (!(nlinks > 1 && hardlinks[nlinks-1] != ix))
798 sb->st_size = rpmfilesFSize(fi, ix);
799 } else if (S_ISLNK(sb->st_mode)) {
801 * Normally rpmfilesFSize() is correct for symlinks too, this is
802 * only needed for glob()'ed links from fakechroot environment.
804 sb->st_size = strlen(rpmfilesFLink(fi, ix));
807 if (user && rpmugUid(user, &sb->st_uid)) {
809 rpmlog(RPMLOG_WARNING,
810 _("user %s does not exist - using %s\n"), user, UID_0_USER);
811 sb->st_mode &= ~S_ISUID; /* turn off suid bit */
814 if (group && rpmugGid(group, &sb->st_gid)) {
816 rpmlog(RPMLOG_WARNING,
817 _("group %s does not exist - using %s\n"), group, GID_0_GROUP);
818 sb->st_mode &= ~S_ISGID; /* turn off sgid bit */
826 struct fingerPrint_s *rpmfilesFps(rpmfiles fi)
828 return (fi != NULL) ? fi->fps : NULL;
831 static int iterFwd(rpmfi fi)
836 static int iterBack(rpmfi fi)
841 static int iterInterval(rpmfi fi)
844 return fi->intervalStart;
845 else if (fi->i + 1 < fi->intervalEnd)
848 return RPMERR_ITER_END;
851 int rpmfiNext(rpmfi fi)
857 } while (next == RPMERR_ITER_SKIP);
859 if (next >= 0 && next < rpmfilesFC(fi->files)) {
861 fi->j = rpmfilesDI(fi->files, fi->i);
872 rpmfi rpmfiInit(rpmfi fi, int fx)
875 if (fx >= 0 && fx < rpmfilesFC(fi->files)) {
884 int rpmfiNextD(rpmfi fi)
888 if (fi != NULL && ++fi->j >= 0) {
889 if (fi->j < rpmfilesDC(fi->files))
898 rpmfi rpmfiInitD(rpmfi fi, int dx)
901 if (dx >= 0 && dx < rpmfilesFC(fi->files))
910 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
912 if (S_ISDIR(mode)) return XDIR;
913 if (S_ISCHR(mode)) return CDEV;
914 if (S_ISBLK(mode)) return BDEV;
915 if (S_ISLNK(mode)) return LINK;
916 if (S_ISSOCK(mode)) return SOCK;
917 if (S_ISFIFO(mode)) return PIPE;
921 int rpmfilesCompare(rpmfiles afi, int aix, rpmfiles bfi, int bix)
923 mode_t amode = rpmfilesFMode(afi, aix);
924 mode_t bmode = rpmfilesFMode(bfi, bix);
925 rpmFileTypes awhat = rpmfiWhatis(amode);
927 if ((rpmfilesFFlags(afi, aix) & RPMFILE_GHOST) ||
928 (rpmfilesFFlags(bfi, bix) & RPMFILE_GHOST)) return 0;
930 /* Mode difference is a conflict, except for symlinks */
931 if (!(awhat == LINK && rpmfiWhatis(bmode) == LINK) && amode != bmode)
934 if (awhat == LINK || awhat == REG) {
935 if (rpmfilesFSize(afi, aix) != rpmfilesFSize(bfi, bix))
939 if (!rstreq(rpmfilesFUser(afi, aix), rpmfilesFUser(bfi, bix)))
941 if (!rstreq(rpmfilesFGroup(afi, aix), rpmfilesFGroup(bfi, bix)))
945 const char * alink = rpmfilesFLink(afi, aix);
946 const char * blink = rpmfilesFLink(bfi, bix);
947 if (alink == blink) return 0;
948 if (alink == NULL) return 1;
949 if (blink == NULL) return -1;
950 return strcmp(alink, blink);
951 } else if (awhat == REG) {
952 size_t adiglen, bdiglen;
954 const unsigned char * adigest, * bdigest;
955 adigest = rpmfilesFDigest(afi, aix, &aalgo, &adiglen);
956 bdigest = rpmfilesFDigest(bfi, bix, &balgo, &bdiglen);
957 if (adigest == bdigest) return 0;
958 if (adigest == NULL) return 1;
959 if (bdigest == NULL) return -1;
960 /* can't meaningfully compare different hash types */
961 if (aalgo != balgo || adiglen != bdiglen) return -1;
962 return memcmp(adigest, bdigest, adiglen);
963 } else if (awhat == CDEV || awhat == BDEV) {
964 if (rpmfilesFRdev(afi, aix) != rpmfilesFRdev(bfi, bix))
971 int rpmfileContentsEqual(rpmfiles ofi, int oix, rpmfiles nfi, int nix)
973 char * fn = rpmfilesFN(nfi, nix);
974 rpmFileTypes diskWhat, newWhat, oldWhat;
978 if (fn == NULL || (lstat(fn, &sb))) {
979 goto exit; /* The file doesn't exist on the disk */
982 if (rpmfilesFSize(nfi, nix) != sb.st_size) {
986 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
987 newWhat = rpmfiWhatis(rpmfilesFMode(nfi, nix));
988 oldWhat = rpmfiWhatis(rpmfilesFMode(ofi, oix));
989 if ((diskWhat != newWhat) || (diskWhat != oldWhat)) {
993 if (diskWhat == REG) {
995 size_t odiglen, ndiglen;
996 const unsigned char * odigest, * ndigest;
999 odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
1000 ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
1001 /* See if the file in old pkg is identical to the one in new pkg */
1002 if ((oalgo != nalgo) || (odiglen != ndiglen) || (!ndigest) ||
1003 (memcmp(odigest, ndigest, ndiglen) != 0)) {
1007 if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL) != 0) {
1008 goto exit; /* assume file has been removed */
1011 /* See if the file on disk is identical to the one in new pkg */
1012 if (memcmp(ndigest, buffer, ndiglen) == 0) {
1016 } else if (diskWhat == LINK) {
1017 const char * nFLink;
1021 nFLink = rpmfilesFLink(nfi, nix);
1022 link_len = readlink(fn, buffer, sizeof(buffer) - 1);
1023 if (link_len == -1) {
1024 goto exit; /* assume file has been removed */
1026 buffer[link_len] = '\0';
1027 /* See if the link on disk is identical to the one in new pkg */
1028 if (nFLink && rstreq(nFLink, buffer)) {
1040 rpmFileAction rpmfilesDecideFate(rpmfiles ofi, int oix,
1041 rpmfiles nfi, int nix,
1044 char * fn = rpmfilesFN(nfi, nix);
1045 rpmfileAttrs newFlags = rpmfilesFFlags(nfi, nix);
1047 rpmFileTypes dbWhat, newWhat, diskWhat;
1049 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
1050 int action = FA_CREATE; /* assume we can create */
1052 /* If the new file is a ghost, leave whatever might be on disk alone. */
1053 if (newFlags & RPMFILE_GHOST) {
1058 if (lstat(fn, &sb)) {
1060 * The file doesn't exist on the disk. Create it unless the new
1061 * package has marked it as missingok, or allfiles is requested.
1063 if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
1064 rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
1073 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
1074 dbWhat = rpmfiWhatis(rpmfilesFMode(ofi, oix));
1075 newWhat = rpmfiWhatis(rpmfilesFMode(nfi, nix));
1078 * This order matters - we'd prefer to TOUCH the file if at all
1079 * possible in case something else (like the timestamp) has changed.
1080 * Only regular files and symlinks might need a backup, everything
1081 * else falls through here with FA_CREATE.
1083 if (dbWhat == REG) {
1085 size_t odiglen, ndiglen;
1086 const unsigned char * odigest, * ndigest;
1088 /* See if the file on disk is identical to the one in new pkg */
1089 ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
1090 if (diskWhat == REG && newWhat == REG) {
1091 if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL))
1092 goto exit; /* assume file has been removed */
1093 if (ndigest && memcmp(ndigest, buffer, ndiglen) == 0) {
1095 goto exit; /* unmodified config file, touch it. */
1099 /* See if the file on disk is identical to the one in old pkg */
1100 odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
1101 if (diskWhat == REG) {
1102 /* hash algo changed or digest was not computed, recalculate it */
1103 if ((oalgo != nalgo) || (newWhat != REG)) {
1104 if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL))
1105 goto exit; /* assume file has been removed */
1107 if (odigest && memcmp(odigest, buffer, odiglen) == 0)
1108 goto exit; /* unmodified config file, replace. */
1111 /* if new file is no longer config, backup it and replace it */
1112 if (!(newFlags & RPMFILE_CONFIG)) {
1117 /* If file can be determined identical in old and new pkg, let it be */
1118 if (newWhat == REG && oalgo == nalgo && odiglen == ndiglen) {
1119 if (odigest && ndigest && memcmp(odigest, ndigest, odiglen) == 0) {
1120 action = FA_SKIP; /* identical file, dont bother */
1125 /* ...but otherwise a backup will be needed */
1127 } else if (dbWhat == LINK) {
1128 const char * oFLink, * nFLink;
1130 if (diskWhat == LINK) {
1131 /* Read link from the disk */
1132 ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
1134 goto exit; /* assume file has been removed */
1135 buffer[link_len] = '\0';
1138 /* See if the link on disk is identical to the one in new pkg */
1139 nFLink = rpmfilesFLink(nfi, nix);
1140 if (diskWhat == LINK && newWhat == LINK) {
1141 if (nFLink && rstreq(nFLink, buffer)) {
1143 goto exit; /* unmodified config file, touch it. */
1147 /* See if the link on disk is identical to the one in old pkg */
1148 oFLink = rpmfilesFLink(ofi, oix);
1149 if (diskWhat == LINK) {
1150 if (oFLink && rstreq(oFLink, buffer))
1151 goto exit; /* unmodified config file, replace. */
1154 /* if new file is no longer config, backup it and replace it */
1155 if (!(newFlags & RPMFILE_CONFIG)) {
1160 /* If link is identical in old and new pkg, let it be */
1161 if (newWhat == LINK && oFLink && nFLink && rstreq(oFLink, nFLink)) {
1162 action = FA_SKIP; /* identical file, don't bother. */
1166 /* ...but otherwise a backup will be needed */
1175 int rpmfilesConfigConflict(rpmfiles fi, int ix)
1178 rpmfileAttrs flags = rpmfilesFFlags(fi, ix);
1180 rpmFileTypes newWhat, diskWhat;
1184 /* Non-configs are not config conflicts. */
1185 if (!(flags & RPMFILE_CONFIG))
1188 /* Only links and regular files can be %config, this is kinda moot */
1189 /* XXX: Why are we returning 1 here? */
1190 newWhat = rpmfiWhatis(rpmfilesFMode(fi, ix));
1191 if (newWhat != LINK && newWhat != REG)
1194 /* If it's not on disk, there's nothing to be saved */
1195 fn = rpmfilesFN(fi, ix);
1200 * Preserve legacy behavior: an existing %ghost %config is considered
1201 * "modified" but unlike regular %config, its never removed and
1202 * never backed up. Whether this actually makes sense is a whole
1203 * another question, but this is very long-standing behavior that
1204 * people might be depending on. The resulting FA_ALTNAME etc action
1205 * is special-cased in FSM to avoid actually creating backups on ghosts.
1207 if (flags & RPMFILE_GHOST) {
1212 /* Files of different types obviously are not identical */
1213 diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
1214 if (diskWhat != newWhat) {
1219 /* Files of different sizes obviously are not identical */
1220 if (rpmfilesFSize(fi, ix) != sb.st_size) {
1225 memset(buffer, 0, sizeof(buffer));
1226 if (newWhat == REG) {
1229 const unsigned char *ndigest = rpmfilesFDigest(fi,ix, &algo, &diglen);
1230 if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer, NULL))
1231 goto exit; /* assume file has been removed */
1232 if (ndigest && memcmp(ndigest, buffer, diglen) == 0)
1233 goto exit; /* unmodified config file */
1234 } else /* newWhat == LINK */ {
1235 const char * nFLink;
1236 ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
1238 goto exit; /* assume file has been removed */
1239 buffer[link_len] = '\0';
1240 nFLink = rpmfilesFLink(fi, ix);
1241 if (nFLink && rstreq(nFLink, buffer))
1242 goto exit; /* unmodified config file */
1252 rpmfiles rpmfilesFree(rpmfiles fi)
1254 if (fi == NULL) return NULL;
1257 return rpmfilesUnlink(fi);
1259 if (rpmfilesFC(fi) > 0) {
1260 if (fi->ofndata != &fi->fndata) {
1261 rpmfnClear(fi->ofndata);
1264 rpmfnClear(&fi->fndata);
1266 fi->flinks = _free(fi->flinks);
1267 fi->flangs = _free(fi->flangs);
1268 fi->digests = _free(fi->digests);
1269 fi->signatures = _free(fi->signatures);
1270 fi->fcaps = _free(fi->fcaps);
1272 fi->cdict = _free(fi->cdict);
1274 fi->fuser = _free(fi->fuser);
1275 fi->fgroup = _free(fi->fgroup);
1277 fi->fstates = _free(fi->fstates);
1278 fi->fps = _free(fi->fps);
1280 /* these point to header memory if KEEPHEADER is used, dont free */
1281 if (!(fi->fiflags & RPMFI_KEEPHEADER) && fi->h == NULL) {
1282 fi->fmtimes = _free(fi->fmtimes);
1283 fi->fmodes = _free(fi->fmodes);
1284 fi->fflags = _free(fi->fflags);
1285 fi->vflags = _free(fi->vflags);
1286 fi->fsizes = _free(fi->fsizes);
1287 fi->lfsizes = _free(fi->lfsizes);
1288 fi->frdevs = _free(fi->frdevs);
1289 fi->finodes = _free(fi->finodes);
1291 fi->fcolors = _free(fi->fcolors);
1292 fi->fcdictx = _free(fi->fcdictx);
1293 fi->ddict = _free(fi->ddict);
1294 fi->fddictx = _free(fi->fddictx);
1295 fi->fddictn = _free(fi->fddictn);
1300 fi->replacedSizes = _free(fi->replacedSizes);
1301 fi->replacedLSizes = _free(fi->replacedLSizes);
1303 fi->h = headerFree(fi->h);
1304 fi->pool = rpmstrPoolFree(fi->pool);
1306 fi->nlinks = nlinkHashFree(fi->nlinks);
1308 (void) rpmfilesUnlink(fi);
1309 memset(fi, 0, sizeof(*fi)); /* XXX trash and burn */
1315 rpmfi rpmfiFree(rpmfi fi)
1317 if (fi == NULL) return NULL;
1320 return rpmfiUnlink(fi);
1322 fi->files = rpmfilesFree(fi->files);
1323 fi->fn = _free(fi->fn);
1324 fi->ofn = _free(fi->ofn);
1325 fi->found = _free(fi->found);
1326 fi->archive = rpmcpioFree(fi->archive);
1332 static rpmsid * tag2pool(rpmstrPool pool, Header h, rpmTag tag, rpm_count_t size)
1334 rpmsid *sids = NULL;
1336 if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
1337 if ((size >= 0) && (rpmtdCount(&td) == size)) { /* ensure right size */
1338 sids = rpmtdToPool(&td, pool);
1345 /* validate a indexed tag data triplet (such as file bn/dn/dx) */
1346 static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd)
1349 uint32_t xc = rpmtdCount(xd);
1350 uint32_t yc = rpmtdCount(yd);
1351 uint32_t zc = rpmtdCount(zd);
1353 /* check that the amount of data in each is sane */
1354 /* normally yc <= xc but larger values are not fatal (RhBug:1001553) */
1355 if (xc > 0 && yc > 0 && zc == xc) {
1356 uint32_t * i, nvalid = 0;
1357 /* ...and that the indexes are within bounds */
1358 while ((i = rpmtdNextUint32(zd))) {
1363 /* unless the loop runs to finish, the data is broken */
1364 sane = (nvalid == zc);
1369 /* Get file data from header */
1370 /* Requires totalfc to be set and label err: to goto on error */
1371 #define _hgfi(_h, _tag, _td, _flags, _data) \
1372 if (headerGet((_h), (_tag), (_td), (_flags))) { \
1373 if (rpmtdCount(_td) != totalfc) { \
1374 rpmlog(RPMLOG_ERR, _("Wrong number of entries for tag %s: %u found but %u expected.\n"), rpmTagGetName(_tag), rpmtdCount(_td), totalfc); \
1377 if (rpmTagGetTagType(_tag) != RPM_STRING_ARRAY_TYPE && rpmTagGetTagType(_tag) != RPM_I18NSTRING_TYPE && \
1378 (_td)->size < totalfc * sizeof(*(_data))) { \
1379 rpmlog(RPMLOG_ERR, _("Malformed data for tag %s: %u bytes found but %u expected.\n"), rpmTagGetName(_tag), (_td)->size, totalfc * sizeof(*(_data))); \
1382 _data = ((_td)->data); \
1384 /* Get file data from header without checking number of entries */
1385 #define _hgfinc(_h, _tag, _td, _flags, _data) \
1386 if (headerGet((_h), (_tag), (_td), (_flags))) {\
1387 _data = ((_td)->data); \
1390 /*** Hard link handling ***/
1400 #define HASHTYPE fileidHash
1401 #define HTKEYTYPE struct fileid_s
1402 #define HTDATATYPE int
1403 #include "lib/rpmhash.H"
1404 #include "lib/rpmhash.C"
1409 static unsigned int fidHashFunc(struct fileid_s a)
1411 return a.id_ino + (a.id_dev<<16) + (a.id_dev>>16);
1414 static int fidCmp(struct fileid_s a, struct fileid_s b)
1416 return !((a.id_dev == b.id_dev) && (a.id_ino == b.id_ino));
1419 static unsigned int intHash(int a)
1421 return a < 0 ? UINT_MAX-a : a;
1424 static int intCmp(int a, int b)
1429 static struct hardlinks_s * freeNLinks(struct hardlinks_s * nlinks)
1432 if (!nlinks->nlink) {
1433 nlinks = _free(nlinks);
1438 static void rpmfilesBuildNLink(rpmfiles fi, Header h)
1440 struct fileid_s f_id;
1442 rpm_dev_t * fdevs = NULL;
1445 int totalfc = rpmfilesFC(fi);
1450 _hgfi(h, RPMTAG_FILEDEVICES, &td, HEADERGET_ALLOC, fdevs);
1454 files = fileidHashCreate(totalfc, fidHashFunc, fidCmp, NULL, NULL);
1455 for (int i=0; i < totalfc; i++) {
1456 if (!S_ISREG(rpmfilesFMode(fi, i)) ||
1457 (rpmfilesFFlags(fi, i) & RPMFILE_GHOST) ||
1458 fi->finodes[i] <= 0) {
1462 f_id.id_dev = fdevs[i];
1463 f_id.id_ino = fi->finodes[i];
1464 fileidHashAddEntry(files, f_id, i);
1466 if (fileidHashNumKeys(files) != fc) {
1468 fi->nlinks = nlinkHashCreate(2*(totalfc - fileidHashNumKeys(files)),
1469 intHash, intCmp, NULL, freeNLinks);
1470 for (int i=0; i < totalfc; i++) {
1473 if (!S_ISREG(rpmfilesFMode(fi, i)) ||
1474 (rpmfilesFFlags(fi, i) & RPMFILE_GHOST)) {
1477 f_id.id_dev = fdevs[i];
1478 f_id.id_ino = fi->finodes[i];
1479 fileidHashGetEntry(files, f_id, &data, &fcnt, NULL);
1480 if (fcnt > 1 && !nlinkHashHasEntry(fi->nlinks, i)) {
1481 struct hardlinks_s * hlinks;
1482 hlinks = xmalloc(sizeof(struct hardlinks_s)+
1483 fcnt*sizeof(hlinks->files[0]));
1484 hlinks->nlink = fcnt;
1485 for (int j=0; j<fcnt; j++) {
1486 hlinks->files[j] = data[j];
1487 nlinkHashAddEntry(fi->nlinks, data[j], hlinks);
1493 files = fileidHashFree(files);
1498 /* Convert a tag of hex strings to binary presentation */
1499 static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
1502 uint8_t *bin = NULL;
1504 if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
1505 uint8_t *t = bin = xmalloc(num * len);
1508 while ((s = rpmtdNextString(&td))) {
1514 for (int j = 0; j < len; j++, t++, s += 2)
1515 *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
1523 static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
1525 headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ?
1526 HEADERGET_MINMEM : HEADERGET_ALLOC;
1527 headerGetFlags defFlags = HEADERGET_ALLOC;
1528 struct rpmtd_s digalgo, td;
1529 rpm_count_t totalfc = rpmfilesFC(fi);
1531 /* XXX TODO: all these should be sanity checked, ugh... */
1532 if (!(flags & RPMFI_NOFILEMODES))
1533 _hgfi(h, RPMTAG_FILEMODES, &td, scareFlags, fi->fmodes);
1534 if (!(flags & RPMFI_NOFILEFLAGS))
1535 _hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
1536 if (!(flags & RPMFI_NOFILEVERIFYFLAGS))
1537 _hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
1538 if (!(flags & RPMFI_NOFILESIZES)) {
1539 _hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
1540 _hgfi(h, RPMTAG_LONGFILESIZES, &td, scareFlags, fi->lfsizes);
1542 if (!(flags & RPMFI_NOFILECOLORS))
1543 _hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
1545 if (!(flags & RPMFI_NOFILECLASS)) {
1546 _hgfinc(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
1547 fi->ncdict = rpmtdCount(&td);
1548 _hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
1550 if (!(flags & RPMFI_NOFILEDEPS)) {
1551 _hgfinc(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
1552 fi->nddict = rpmtdCount(&td);
1553 _hgfinc(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
1554 _hgfinc(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
1557 if (!(flags & RPMFI_NOFILESTATES))
1558 _hgfi(h, RPMTAG_FILESTATES, &td, defFlags, fi->fstates);
1560 if (!(flags & RPMFI_NOFILECAPS))
1561 _hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps);
1563 if (!(flags & RPMFI_NOFILELINKTOS))
1564 fi->flinks = tag2pool(fi->pool, h, RPMTAG_FILELINKTOS, totalfc);
1565 /* FILELANGS are only interesting when installing */
1566 if ((headerGetInstance(h) == 0) && !(flags & RPMFI_NOFILELANGS))
1567 fi->flangs = tag2pool(fi->pool, h, RPMTAG_FILELANGS, totalfc);
1569 /* See if the package has non-md5 file digests */
1570 fi->digestalgo = PGPHASHALGO_MD5;
1571 if (headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM)) {
1572 uint32_t *algo = rpmtdGetUint32(&digalgo);
1573 /* Hmm, what to do with unknown digest algorithms? */
1574 if (algo && rpmDigestLength(*algo) != 0) {
1575 fi->digestalgo = *algo;
1580 /* grab hex digests from header and store in binary format */
1581 if (!(flags & RPMFI_NOFILEDIGESTS)) {
1582 size_t diglen = rpmDigestLength(fi->digestalgo);
1583 fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen);
1586 fi->signatures = NULL;
1587 /* grab hex signatures from header and store in binary format */
1588 if (!(flags & RPMFI_NOFILESIGNATURES)) {
1589 fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
1590 fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
1591 totalfc, fi->signaturelength);
1594 /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
1595 if (!(flags & RPMFI_NOFILEMTIMES))
1596 _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
1597 if (!(flags & RPMFI_NOFILERDEVS))
1598 _hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
1599 if (!(flags & RPMFI_NOFILEINODES)) {
1600 _hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
1601 rpmfilesBuildNLink(fi, h);
1603 if (!(flags & RPMFI_NOFILEUSER)) {
1604 fi->fuser = tag2pool(fi->pool, h, RPMTAG_FILEUSERNAME, totalfc);
1605 if (!fi->fuser) goto err;
1607 if (!(flags & RPMFI_NOFILEGROUP)) {
1608 fi->fgroup = tag2pool(fi->pool, h, RPMTAG_FILEGROUPNAME, totalfc);
1609 if (!fi->fgroup) goto err;
1611 /* TODO: validate and return a real error */
1617 rpmfiles rpmfilesNew(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
1619 rpmfiles fi = xcalloc(1, sizeof(*fi));
1622 fi->magic = RPMFIMAGIC;
1623 fi->fiflags = flags;
1624 /* private or shared pool? */
1625 fi->pool = (pool != NULL) ? rpmstrPoolLink(pool) : rpmstrPoolCreate();
1628 * Grab and validate file triplet data. Headers with no files simply
1629 * fall through here and an empty file set is returned.
1631 fc = rpmfnInit(&fi->fndata, RPMTAG_BASENAMES, h, fi->pool);
1633 /* Broken data, bail out */
1637 /* populate the rest of the stuff if we have files */
1639 if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
1640 /* For relocated packages, grab the original paths too */
1642 fi->ofndata = xmalloc(sizeof(*fi->ofndata));
1643 ofc = rpmfnInit(fi->ofndata, RPMTAG_ORIGBASENAMES, h, fi->pool);
1645 if (ofc != 0 && ofc != fc)
1648 /* In the normal case, orig is the same as actual path data */
1649 fi->ofndata = &fi->fndata;
1652 if (rpmfilesPopulate(fi, h, flags))
1656 /* freeze the pool to save memory, but only if private pool */
1657 if (fi->pool != pool)
1658 rpmstrPoolFreeze(fi->pool, 0);
1660 fi->h = (fi->fiflags & RPMFI_KEEPHEADER) ? headerLink(h) : NULL;
1662 return rpmfilesLink(fi);
1669 static int iterWriteArchiveNext(rpmfi fi);
1670 static int iterReadArchiveNext(rpmfi fi);
1671 static int iterReadArchiveNextContentFirst(rpmfi fi);
1672 static int iterReadArchiveNextOmitHardlinks(rpmfi fi);
1674 static int (*nextfuncs[])(rpmfi fi) = {
1677 iterWriteArchiveNext,
1678 iterReadArchiveNext,
1679 iterReadArchiveNextContentFirst,
1680 iterReadArchiveNextOmitHardlinks,
1685 static rpmfi initIter(rpmfiles files, int itype, int link)
1689 if (files && itype>=0 && itype<=RPMFILEITERMAX) {
1690 fi = xcalloc(1, sizeof(*fi));
1692 fi->files = link ? rpmfilesLink(files) : files;
1693 fi->next = nextfuncs[itype];
1695 if (itype == RPMFI_ITER_BACK) {
1696 fi->i = rpmfilesFC(fi->files);
1697 } else if (itype >=RPMFI_ITER_READ_ARCHIVE
1698 && itype <= RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS) {
1700 fi->found = xcalloc(1, (rpmfiFC(fi)>>3) + 1);
1707 rpmfi rpmfilesIter(rpmfiles files, int itype)
1709 /* standalone iterators need to bump our refcount */
1710 return initIter(files, itype, 1);
1713 rpmfi rpmfilesFindPrefix(rpmfiles fi, const char *pfx)
1715 int l, u, c, comparison;
1716 rpmfi iterator = NULL;
1721 size_t plen = strlen(pfx);
1727 comparison = cmpPfx(fi, c, pfx, plen);
1731 else if (comparison > 0)
1734 if (cmpPfx(fi, l, pfx, plen))
1736 while (l > 0 && !cmpPfx(fi, l - 1, pfx, plen))
1738 if ( u >= rpmfilesFC(fi) || cmpPfx(fi, u, pfx, plen))
1740 while (++u < rpmfilesFC(fi)) {
1741 if (cmpPfx(fi, u, pfx, plen))
1750 iterator = initIter(fi, RPMFI_ITER_INTERVAL, 1);
1751 iterator->intervalStart = l;
1752 iterator->intervalEnd = u;
1758 rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
1760 rpmfiles files = rpmfilesNew(pool, h, tagN, flags);
1761 /* we already own rpmfiles, avoid extra refcount on it */
1762 return initIter(files, RPMFI_ITER_FWD, 0);
1765 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTagVal tagN, rpmfiFlags flags)
1767 return rpmfiNewPool(NULL, h, tagN, flags);
1770 void rpmfilesSetFReplacedSize(rpmfiles fi, int ix, rpm_loff_t newsize)
1772 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
1773 /* Switch over to 64 bit variant */
1774 int fc = rpmfilesFC(fi);
1775 if (newsize > UINT32_MAX && fi->replacedLSizes == NULL) {
1776 fi->replacedLSizes = xcalloc(fc, sizeof(*fi->replacedLSizes));
1777 /* copy 32 bit data */
1778 if (fi->replacedSizes) {
1779 for (int i=0; i < fc; i++)
1780 fi->replacedLSizes[i] = fi->replacedSizes[i];
1781 fi->replacedSizes = _free(fi->replacedSizes);
1784 if (fi->replacedLSizes != NULL) {
1785 fi->replacedLSizes[ix] = newsize;
1787 if (fi->replacedSizes == NULL)
1788 fi->replacedSizes = xcalloc(fc, sizeof(*fi->replacedSizes));
1789 fi->replacedSizes[ix] = (rpm_off_t) newsize;
1794 rpm_loff_t rpmfilesFReplacedSize(rpmfiles fi, int ix)
1796 rpm_loff_t rsize = 0;
1797 if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
1798 if (fi->replacedSizes) {
1799 rsize = fi->replacedSizes[ix];
1800 } else if (fi->replacedLSizes) {
1801 rsize = fi->replacedLSizes[ix];
1807 void rpmfilesFpLookup(rpmfiles fi, fingerPrintCache fpc)
1809 /* This can get called twice (eg yum), scratch former results and redo */
1810 if (rpmfilesFC(fi) > 0) {
1811 rpmfn fn = &fi->fndata;
1814 fi->fps = fpLookupList(fpc, fi->pool,
1815 fn->dnid, fn->bnid, fn->dil, fn->fc);
1820 * Generate iterator accessors function wrappers, these do nothing but
1821 * call the corresponding rpmfiFooIndex(fi, fi->[ij])
1824 #define RPMFI_ITERFUNC(TYPE, NAME, IXV) \
1825 TYPE rpmfi ## NAME(rpmfi fi) { return rpmfiles ## NAME(fi ? fi->files : NULL, fi ? fi->IXV : -1); }
1827 RPMFI_ITERFUNC(rpmsid, BNId, i)
1828 RPMFI_ITERFUNC(rpmsid, DNId, j)
1829 RPMFI_ITERFUNC(const char *, BN, i)
1830 RPMFI_ITERFUNC(const char *, DN, j)
1831 RPMFI_ITERFUNC(const char *, OBN, i)
1832 RPMFI_ITERFUNC(const char *, ODN, j)
1833 RPMFI_ITERFUNC(const char *, FLink, i)
1834 RPMFI_ITERFUNC(const char *, FUser, i)
1835 RPMFI_ITERFUNC(const char *, FGroup, i)
1836 RPMFI_ITERFUNC(const char *, FCaps, i)
1837 RPMFI_ITERFUNC(const char *, FLangs, i)
1838 RPMFI_ITERFUNC(const char *, FClass, i)
1839 RPMFI_ITERFUNC(rpmfileState, FState, i)
1840 RPMFI_ITERFUNC(rpmfileAttrs, FFlags, i)
1841 RPMFI_ITERFUNC(rpmVerifyAttrs, VFlags, i)
1842 RPMFI_ITERFUNC(rpm_mode_t, FMode, i)
1843 RPMFI_ITERFUNC(rpm_rdev_t, FRdev, i)
1844 RPMFI_ITERFUNC(rpm_time_t, FMtime, i)
1845 RPMFI_ITERFUNC(rpm_ino_t, FInode, i)
1846 RPMFI_ITERFUNC(rpm_loff_t, FSize, i)
1847 RPMFI_ITERFUNC(rpm_color_t, FColor, i)
1848 RPMFI_ITERFUNC(uint32_t, FNlink, i)
1850 const char * rpmfiFN(rpmfi fi)
1852 const char *fn = ""; /* preserve behavior on errors */
1855 fi->fn = rpmfilesFN(fi->files, fi->i);
1862 const char * rpmfiOFN(rpmfi fi)
1864 const char *fn = ""; /* preserve behavior on errors */
1867 fi->ofn = rpmfilesOFN(fi->files, fi->i);
1868 if (fi->ofn != NULL)
1874 const unsigned char * rpmfiFDigest(rpmfi fi, int *algo, size_t *len)
1876 return rpmfilesFDigest(fi->files, fi ? fi->i : -1, algo, len);
1879 const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
1881 return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
1884 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
1886 return rpmfilesFDepends(fi->files, fi ? fi->i : -1, fddictp);
1889 int rpmfiStat(rpmfi fi, int flags, struct stat *sb)
1891 return rpmfilesStat(fi->files, fi->i, flags, sb);
1894 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
1896 return rpmfilesCompare(afi->files, afi ? afi->i : -1, bfi->files, bfi ? bfi->i : -1);
1899 rpmVerifyAttrs rpmfiVerify(rpmfi fi, rpmVerifyAttrs omitMask)
1901 return rpmfilesVerify(fi->files, fi->i, omitMask);
1904 rpmstrPool rpmfilesPool(rpmfiles fi)
1906 return (fi != NULL) ? fi->pool : NULL;
1909 rpmfiles rpmfiFiles(rpmfi fi)
1911 return (fi != NULL) ? fi->files : NULL;
1914 /******************************************************/
1915 /*** Archive handling *********************************/
1916 /******************************************************/
1918 rpmfi rpmfiNewArchiveReader(FD_t fd, rpmfiles files, int itype)
1920 rpmcpio_t archive = rpmcpioOpen(fd, O_RDONLY);
1922 if (archive && itype >= RPMFI_ITER_READ_ARCHIVE) {
1923 fi = rpmfilesIter(files, itype);
1926 fi->archive = archive;
1928 rpmcpioFree(archive);
1933 rpmfi rpmfiNewArchiveWriter(FD_t fd, rpmfiles files)
1935 rpmcpio_t archive = rpmcpioOpen(fd, O_WRONLY);
1938 fi = rpmfilesIter(files, RPMFI_ITER_WRITE_ARCHIVE);
1941 fi->archive = archive;
1943 rpmcpioFree(archive);
1948 int rpmfiArchiveClose(rpmfi fi)
1952 int rc = rpmcpioClose(fi->archive);
1956 rpm_loff_t rpmfiArchiveTell(rpmfi fi)
1958 if (fi == NULL || fi->archive == NULL)
1960 return (rpm_loff_t) rpmcpioTell(fi->archive);
1963 static int rpmfiArchiveWriteHeader(rpmfi fi)
1968 if (rpmfiStat(fi, 0, &st))
1971 rpmfiles files = fi->files;
1973 if (files->lfsizes) {
1974 return rpmcpioStrippedHeaderWrite(fi->archive, rpmfiFX(fi), st.st_size);
1976 const char * dn = rpmfiDN(fi);
1977 char * path = rstrscat(NULL, (dn[0] == '/' && !rpmExpandNumeric("%{_noPayloadPrefix}")) ? "." : "",
1978 dn, rpmfiBN(fi), NULL);
1979 rc = rpmcpioHeaderWrite(fi->archive, path, &st);
1986 static int iterWriteArchiveNextFile(rpmfi fi)
1988 rpmfiles files = rpmfiFiles(fi);
1989 int fx = rpmfiFX(fi);
1990 int fc = rpmfiFC(fi);
1991 const int * hardlinks;
1992 int numHardlinks = 0;
1994 /* already processing hard linked files */
1995 if (rpmfiFNlink(fi) > 1) {
1996 /* search next hard linked file */
1998 for (int i=fx+1; i<fc; i++) {
2000 if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
2002 numHardlinks = rpmfilesFLinks(files, i, &hardlinks);
2003 if (numHardlinks > 1 && hardlinks[0] == i) {
2010 /* search next non hardlinked file */
2011 for (int i=fx+1; i<fc; i++) {
2013 if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
2015 if (rpmfilesFNlink(files, i) < 2) {
2020 if (rpmfiFX(fi) == -1) {
2021 /* continue with first hard linked file */
2022 for (int i=0; i<fc; i++) {
2024 if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
2026 numHardlinks = rpmfilesFLinks(files, i, &hardlinks);
2027 if (numHardlinks > 1) {
2034 if (rpmfiFX(fi) == -1)
2037 /* write header(s) */
2038 if (numHardlinks>1) {
2039 for (int i=0; i<numHardlinks; i++) {
2040 rpmfiSetFX(fi, hardlinks[i]);
2041 int rc = rpmfiArchiveWriteHeader(fi);
2046 rpmfiSetFX(fi, hardlinks[0]);
2048 int rc = rpmfiArchiveWriteHeader(fi);
2056 static int iterWriteArchiveNext(rpmfi fi)
2059 /* loop over the files we can handle ourself */
2061 fx = iterWriteArchiveNextFile(fi);
2062 if (S_ISLNK(rpmfiFMode(fi))) {
2063 /* write symlink target */
2064 const char *lnk = rpmfiFLink(fi);
2065 size_t len = strlen(lnk);
2066 if (rpmfiArchiveWrite(fi, lnk, len) != len) {
2067 return RPMERR_WRITE_FAILED;
2069 } else if (S_ISREG(rpmfiFMode(fi)) && rpmfiFSize(fi)) {
2070 /* this file actually needs some content */
2073 /* go on for special files, directories and empty files */
2078 size_t rpmfiArchiveWrite(rpmfi fi, const void * buf, size_t size)
2080 if (fi == NULL || fi->archive == NULL)
2082 return rpmcpioWrite(fi->archive, buf, size);
2085 int rpmfiArchiveWriteFile(rpmfi fi, FD_t fd)
2092 if (fi == NULL || fi->archive == NULL || fd == NULL)
2095 left = rpmfiFSize(fi);
2098 len = (left > sizeof(buf) ? sizeof(buf) : left);
2099 if (Fread(buf, sizeof(*buf), len, fd) != len || Ferror(fd)) {
2100 rc = RPMERR_READ_FAILED;
2104 if (rpmcpioWrite(fi->archive, buf, len) != len) {
2105 rc = RPMERR_WRITE_FAILED;
2113 static void rpmfiSetFound(rpmfi fi, int ix)
2115 fi->found[ix >> 3] |= (1 << (ix % 8));
2118 static int rpmfiFound(rpmfi fi, int ix)
2120 return fi->found[ix >> 3] & (1 << (ix % 8));
2123 static int iterReadArchiveNext(rpmfi fi)
2127 int fc = rpmfilesFC(fi->files);
2130 if (fi->archive == NULL)
2133 /* Read next payload header. */
2134 rc = rpmcpioHeaderRead(fi->archive, &path, &fx);
2136 /* if archive ended, check if we found all files */
2137 if (rc == RPMERR_ITER_END) {
2138 for (int i=0; i<fc; i++) {
2139 if (!rpmfiFound(fi, i) &&
2140 !(rpmfilesFFlags(fi->files, i) & RPMFILE_GHOST)) {
2141 rc = RPMERR_MISSING_FILE;
2151 /* Regular cpio archive, identify mapping index. */
2152 fx = rpmfilesFindOFN(fi->files, path);
2156 if (fx >= 0 && fx < fc) {
2157 rpm_loff_t fsize = 0;
2158 rpm_mode_t mode = rpmfilesFMode(fi->files, fx);
2160 /* %ghost in payload, should not be there but rpm < 4.11 sometimes did this */
2161 if (rpmfilesFFlags(fi->files, fx) & RPMFILE_GHOST)
2162 return RPMERR_ITER_SKIP;
2164 if (S_ISREG(mode)) {
2166 uint32_t numlinks = rpmfilesFLinks(fi->files, fx, &links);
2167 if (!(numlinks > 1 && links[numlinks-1] != fx))
2168 fsize = rpmfilesFSize(fi->files, fx);
2169 } else if (S_ISLNK(mode)) {
2170 /* Skip over symlink target data in payload */
2171 rpm_loff_t lsize = rpmfilesFSize(fi->files, fx);
2172 char *buf = xmalloc(lsize + 1);
2173 if (rpmcpioRead(fi->archive, buf, lsize) != lsize)
2174 rc = RPMERR_READ_FAILED;
2175 /* XXX should we validate the payload matches? */
2178 rpmcpioSetExpectedFileSize(fi->archive, fsize);
2179 rpmfiSetFound(fi, fx);
2182 rc = RPMERR_UNMAPPED_FILE;
2184 return (rc != 0) ? rc : fx;
2188 static int iterReadArchiveNextOmitHardlinks(rpmfi fi)
2194 fx = iterReadArchiveNext(fi);
2195 nlink = rpmfilesFLinks(fi->files, fx, &links);
2196 } while (fx>=0 && nlink>1 && links[nlink-1]!=fx);
2200 static int iterReadArchiveNextContentFirst(rpmfi fi)
2202 int fx = rpmfiFX(fi);
2205 /* decide what to do on the basis of the last entry */
2206 nlink = rpmfilesFLinks(fi->files, fx, &links);
2208 /* currently reading through hard links */
2209 if (fx == links[nlink-1]) {
2210 /* arrived back at last entry, read on */
2211 fx = iterReadArchiveNext(fi);
2213 /* next hard link */
2214 /* scales poorly but shouldn't matter */
2215 for (int i=0; i<nlink; i++) {
2216 if (links[i] == fx) {
2221 /* should never happen */
2225 fx = iterReadArchiveNext(fi);
2228 /* look at the new entry */
2229 nlink = rpmfilesFLinks(fi->files, fx, &links);
2230 /* arrived at new set of hardlinks? */
2232 /* read over all entries to the last one (containing the content) */
2234 fx = iterReadArchiveNext(fi);
2235 } while (fx >=0 && fx != links[nlink-1]);
2236 /* rewind to the first entry */
2244 int rpmfiArchiveHasContent(rpmfi fi)
2247 if (fi && S_ISREG(rpmfiFMode(fi))) {
2249 int nlink = rpmfiFLinks(fi, &links);
2251 if (fi->next == iterReadArchiveNext ||
2252 fi->next == iterReadArchiveNextOmitHardlinks) {
2253 res = rpmfiFX(fi) == links[nlink-1];
2254 } else if (fi->next == iterReadArchiveNextContentFirst) {
2255 res = rpmfiFX(fi) == links[0];
2264 size_t rpmfiArchiveRead(rpmfi fi, void * buf, size_t size)
2266 if (fi == NULL || fi->archive == NULL)
2268 return rpmcpioRead(fi->archive, buf, size);
2271 int rpmfiArchiveReadToFilePsm(rpmfi fi, FD_t fd, int nodigest, rpmpsm psm)
2273 if (fi == NULL || fi->archive == NULL || fd == NULL)
2276 rpm_loff_t left = rpmfiFSize(fi);
2277 const unsigned char * fidigest = NULL;
2278 pgpHashAlgo digestalgo = 0;
2283 digestalgo = rpmfiDigestAlgo(fi);
2284 fidigest = rpmfilesFDigest(fi->files, rpmfiFX(fi), NULL, NULL);
2285 fdInitDigest(fd, digestalgo, 0);
2290 len = (left > sizeof(buf) ? sizeof(buf) : left);
2291 if (rpmcpioRead(fi->archive, buf, len) != len) {
2292 rc = RPMERR_READ_FAILED;
2295 if ((Fwrite(buf, sizeof(*buf), len, fd) != len) || Ferror(fd)) {
2296 rc = RPMERR_WRITE_FAILED;
2300 rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
2305 void * digest = NULL;
2308 fdFiniDigest(fd, digestalgo, &digest, NULL, 0);
2310 if (digest != NULL && fidigest != NULL) {
2311 size_t diglen = rpmDigestLength(digestalgo);
2312 if (memcmp(digest, fidigest, diglen)) {
2313 rc = RPMERR_DIGEST_MISMATCH;
2315 /* ...but in old packages, empty files have zeros for digest */
2316 if (rpmfiFSize(fi) == 0 && digestalgo == PGPHASHALGO_MD5) {
2317 uint8_t zeros[diglen];
2318 memset(&zeros, 0, diglen);
2319 if (memcmp(zeros, fidigest, diglen) == 0)
2324 rc = RPMERR_DIGEST_MISMATCH;
2333 int rpmfiArchiveReadToFile(rpmfi fi, FD_t fd, int nodigest)
2335 return rpmfiArchiveReadToFilePsm(fi, fd, nodigest, NULL);
2338 char * rpmfileStrerror(int rc)
2341 const char *s = NULL;
2342 const char *prefix = "cpio";
2343 int myerrno = errno;
2348 case RPMERR_BAD_MAGIC: s = _("Bad magic"); break;
2349 case RPMERR_BAD_HEADER: s = _("Bad/unreadable header");break;
2351 case RPMERR_OPEN_FAILED: s = "open"; break;
2352 case RPMERR_CHMOD_FAILED: s = "chmod"; break;
2353 case RPMERR_CHOWN_FAILED: s = "chown"; break;
2354 case RPMERR_WRITE_FAILED: s = "write"; break;
2355 case RPMERR_UTIME_FAILED: s = "utime"; break;
2356 case RPMERR_UNLINK_FAILED: s = "unlink"; break;
2357 case RPMERR_RENAME_FAILED: s = "rename"; break;
2358 case RPMERR_SYMLINK_FAILED: s = "symlink"; break;
2359 case RPMERR_STAT_FAILED: s = "stat"; break;
2360 case RPMERR_LSTAT_FAILED: s = "lstat"; break;
2361 case RPMERR_MKDIR_FAILED: s = "mkdir"; break;
2362 case RPMERR_RMDIR_FAILED: s = "rmdir"; break;
2363 case RPMERR_MKNOD_FAILED: s = "mknod"; break;
2364 case RPMERR_MKFIFO_FAILED: s = "mkfifo"; break;
2365 case RPMERR_LINK_FAILED: s = "link"; break;
2366 case RPMERR_READLINK_FAILED: s = "readlink"; break;
2367 case RPMERR_READ_FAILED: s = "read"; break;
2368 case RPMERR_COPY_FAILED: s = "copy"; break;
2369 case RPMERR_LSETFCON_FAILED: s = "lsetfilecon"; break;
2370 case RPMERR_SETCAP_FAILED: s = "cap_set_file"; break;
2372 case RPMERR_HDR_SIZE: s = _("Header size too big"); break;
2373 case RPMERR_FILE_SIZE: s = _("File too large for archive"); break;
2374 case RPMERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
2375 case RPMERR_MISSING_FILE: s = _("Missing file(s)"); break;
2376 case RPMERR_DIGEST_MISMATCH: s = _("Digest mismatch"); break;
2377 case RPMERR_INTERNAL: s = _("Internal error"); break;
2378 case RPMERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
2379 case RPMERR_ENOENT: s = strerror(ENOENT); break;
2380 case RPMERR_ENOTEMPTY: s = strerror(ENOTEMPTY); break;
2381 case RPMERR_EXIST_AS_DIR:
2382 s = _("File from package already exists as a directory in system");
2387 rasprintf(&msg, "%s: %s", prefix, s);
2388 if ((rc <= RPMERR_CHECK_ERRNO) && myerrno) {
2389 rstrscat(&msg, _(" failed - "), strerror(myerrno), NULL);
2392 rasprintf(&msg, _("%s: (error 0x%x)"), prefix, rc);