1 /** \ingroup rpmdep
2  * \file lib/rpmfi.c
3  * Routines to handle file info tag sets.
4  */
5 
6 #include "system.h"
7 
8 #include <rpm/rpmlog.h>
9 #include <rpm/rpmts.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>
14 #include <errno.h>
15 #include <fcntl.h>
16 
17 #include "lib/rpmfi_internal.h"
18 #include "lib/rpmte_internal.h"	/* relocations */
19 #include "lib/cpio.h"	/* XXX CPIO_FOO */
20 #include "lib/fsm.h"	/* rpmpsm stuff for now */
21 #include "lib/rpmug.h"
22 #include "rpmio/rpmio_internal.h"       /* fdInit/FiniDigest */
23 
24 #include "debug.h"
25 
26 struct hardlinks_s {
27     int nlink;
28     int files[];
29 };
30 
31 typedef struct hardlinks_s * hardlinks_t;
32 
33 #undef HASHTYPE
34 #undef HTKEYTYPE
35 #undef HTDATATYPE
36 #define HASHTYPE nlinkHash
37 #define HTKEYTYPE int
38 #define HTDATATYPE struct hardlinks_s *
39 #include "lib/rpmhash.H"
40 #include "lib/rpmhash.C"
41 #undef HASHTYPE
42 #undef HTKEYTYPE
43 #undef HTDATATYPE
44 
45 typedef int (*iterfunc)(rpmfi fi);
46 
47 struct rpmfi_s {
48     int i;			/*!< Current file index. */
49     int j;			/*!< Current directory index. */
50     iterfunc next;		/*!< Iterator function. */
51     char * fn;			/*!< File name buffer. */
52     char * ofn;			/*!< Original file name buffer. */
53 
54     int intervalStart;		/*!< Start of iterating interval. */
55     int intervalEnd;		/*!< End of iterating interval. */
56 
57     rpmfiles files;		/*!< File info set */
58     rpmcpio_t archive;		/*!< Archive with payload */
59     unsigned char * found;	/*!< Bit field of files found in the archive */
60     int nrefs;			/*!< Reference count */
61 };
62 
63 struct rpmfn_s {
64     rpm_count_t dc;		/*!< No. of directories. */
65     rpm_count_t fc;		/*!< No. of files. */
66 
67     rpmsid * bnid;		/*!< Index to base name(s) (pool) */
68     rpmsid * dnid;		/*!< Index to directory name(s) (pool) */
69     uint32_t * dil;		/*!< Directory indice(s) (from header) */
70 };
71 
72 typedef struct rpmfn_s * rpmfn;
73 
74 /**
75  * A package filename set.
76  */
77 struct rpmfiles_s {
78     Header h;			/*!< Header for file info set (or NULL) */
79     rpmstrPool pool;		/*!< String pool of this file info set */
80 
81     struct rpmfn_s fndata;	/*!< File name data */
82     struct rpmfn_s *ofndata;	/*!< Original file name data */
83 
84     rpmsid * flinks;		/*!< Index to file link(s) (pool) */
85 
86     rpm_flag_t * fflags;	/*!< File flag(s) (from header) */
87     rpm_off_t * fsizes;		/*!< File size(s) (from header) */
88     rpm_loff_t * lfsizes;	/*!< File size(s) (from header) */
89     rpm_time_t * fmtimes;	/*!< File modification time(s) (from header) */
90     rpm_mode_t * fmodes;	/*!< File mode(s) (from header) */
91     rpm_rdev_t * frdevs;	/*!< File rdev(s) (from header) */
92     rpm_ino_t * finodes;	/*!< File inodes(s) (from header) */
93 
94     rpmsid * fuser;		/*!< Index to file owner(s) (misc pool) */
95     rpmsid * fgroup;		/*!< Index to file group(s) (misc pool) */
96     rpmsid * flangs;		/*!< Index to file lang(s) (misc pool) */
97 
98     char * fstates;		/*!< File state(s) (from header) */
99 
100     rpm_color_t * fcolors;	/*!< File color bits (header) */
101     char ** fcaps;		/*!< File capability strings (header) */
102 
103     char ** cdict;		/*!< File class dictionary (header) */
104     rpm_count_t ncdict;		/*!< No. of class entries. */
105     uint32_t * fcdictx;		/*!< File class dictionary index (header) */
106 
107     uint32_t * ddict;		/*!< File depends dictionary (header) */
108     rpm_count_t nddict;		/*!< No. of depends entries. */
109     uint32_t * fddictx;		/*!< File depends dictionary start (header) */
110     uint32_t * fddictn;		/*!< File depends dictionary count (header) */
111     rpm_flag_t * vflags;	/*!< File verify flag(s) (from header) */
112 
113     rpmfiFlags fiflags;		/*!< file info set control flags */
114 
115     struct fingerPrint_s * fps;	/*!< File fingerprint(s). */
116 
117     int digestalgo;		/*!< File digest algorithm */
118     int signaturelength;	/*!< File signature length */
119     unsigned char * digests;	/*!< File digests in binary. */
120     unsigned char * signatures; /*!< File signatures in binary. */
121 
122     struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */
123     rpm_off_t * replacedSizes;	/*!< (TR_ADDED) */
124     rpm_loff_t * replacedLSizes;/*!< (TR_ADDED) */
125     int magic;
126     int nrefs;		/*!< Reference count. */
127 };
128 
129 static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd);
130 static int cmpPoolFn(rpmstrPool pool, rpmfn files, int ix, const char * fn);
131 
rpmfilesUnlink(rpmfiles fi)132 static rpmfiles rpmfilesUnlink(rpmfiles fi)
133 {
134     if (fi)
135 	fi->nrefs--;
136     return NULL;
137 }
138 
rpmfilesLink(rpmfiles fi)139 rpmfiles rpmfilesLink(rpmfiles fi)
140 {
141     if (fi)
142 	fi->nrefs++;
143     return fi;
144 }
145 
rpmfiUnlink(rpmfi fi)146 static rpmfi rpmfiUnlink(rpmfi fi)
147 {
148     if (fi)
149 	fi->nrefs--;
150     return NULL;
151 }
152 
rpmfiLink(rpmfi fi)153 rpmfi rpmfiLink(rpmfi fi)
154 {
155     if (fi)
156 	fi->nrefs++;
157     return fi;
158 }
159 
160 /*
161  * Collect and validate file path data from header.
162  * Return the number of files found (could be none) or -1 on error.
163  */
rpmfnInit(rpmfn fndata,rpmTagVal bntag,Header h,rpmstrPool pool)164 static int rpmfnInit(rpmfn fndata, rpmTagVal bntag, Header h, rpmstrPool pool)
165 {
166     struct rpmtd_s bn, dn, dx;
167     rpmTagVal dntag, ditag;
168     int rc = 0;
169 
170     if (bntag == RPMTAG_BASENAMES) {
171 	dntag = RPMTAG_DIRNAMES;
172 	ditag = RPMTAG_DIRINDEXES;
173     } else if (bntag == RPMTAG_ORIGBASENAMES) {
174 	dntag = RPMTAG_ORIGDIRNAMES;
175 	ditag = RPMTAG_ORIGDIRINDEXES;
176     } else {
177 	return -1;
178     }
179 
180     /* Grab and validate file triplet data (if there is any) */
181     if (headerGet(h, bntag, &bn, HEADERGET_MINMEM)) {
182 	headerGet(h, dntag, &dn, HEADERGET_MINMEM);
183 	headerGet(h, ditag, &dx, HEADERGET_ALLOC);
184 
185 	if (indexSane(&bn, &dn, &dx)) {
186 	    /* Init the file triplet data */
187 	    fndata->fc = rpmtdCount(&bn);
188 	    fndata->dc = rpmtdCount(&dn);
189 	    fndata->bnid = rpmtdToPool(&bn, pool);
190 	    fndata->dnid = rpmtdToPool(&dn, pool);
191 	    /* Steal index data from the td (pooh...) */
192 	    fndata->dil = dx.data;
193 	    dx.data = NULL;
194 	    rc = fndata->fc;
195 	} else {
196 	    memset(fndata, 0, sizeof(*fndata));
197 	    rc = -1;
198 	}
199 	rpmtdFreeData(&bn);
200 	rpmtdFreeData(&dn);
201 	rpmtdFreeData(&dx);
202     }
203 
204     return rc;
205 }
206 
rpmfnClear(rpmfn fndata)207 static void rpmfnClear(rpmfn fndata)
208 {
209     if (fndata) {
210 	free(fndata->bnid);
211 	free(fndata->dnid);
212 	free(fndata->dil);
213 	memset(fndata, 0, sizeof(*fndata));
214     }
215 }
216 
rpmfnFC(rpmfn fndata)217 static rpm_count_t rpmfnFC(rpmfn fndata)
218 {
219     return (fndata != NULL) ? fndata->fc :0;
220 }
221 
rpmfnDC(rpmfn fndata)222 static rpm_count_t rpmfnDC(rpmfn fndata)
223 {
224     return (fndata != NULL) ? fndata->dc : 0;
225 }
226 
rpmfnDI(rpmfn fndata,int ix)227 static int rpmfnDI(rpmfn fndata, int ix)
228 {
229     int j = -1;
230     if (ix >= 0 && ix < rpmfnFC(fndata)) {
231 	if (fndata->dil != NULL)
232 	    j = fndata->dil[ix];
233     }
234     return j;
235 }
236 
rpmfnBNId(rpmfn fndata,int ix)237 static rpmsid rpmfnBNId(rpmfn fndata, int ix)
238 {
239     rpmsid id = 0;
240     if (ix >= 0 && ix < rpmfnFC(fndata)) {
241 	if (fndata->bnid != NULL)
242 	    id = fndata->bnid[ix];
243     }
244     return id;
245 }
246 
rpmfnDNId(rpmfn fndata,int ix)247 static rpmsid rpmfnDNId(rpmfn fndata, int ix)
248 {
249     rpmsid id = 0;
250     if (ix >= 0 && ix < rpmfnDC(fndata)) {
251 	if (fndata->dnid != NULL)
252 	    id = fndata->dnid[ix];
253     }
254     return id;
255 }
256 
rpmfnBN(rpmstrPool pool,rpmfn fndata,int ix)257 static const char * rpmfnBN(rpmstrPool pool, rpmfn fndata, int ix)
258 {
259     return rpmstrPoolStr(pool, rpmfnBNId(fndata, ix));
260 }
261 
rpmfnDN(rpmstrPool pool,rpmfn fndata,int ix)262 static const char * rpmfnDN(rpmstrPool pool, rpmfn fndata, int ix)
263 {
264     return rpmstrPoolStr(pool, rpmfnDNId(fndata, ix));
265 }
266 
rpmfnFN(rpmstrPool pool,rpmfn fndata,int ix)267 static char * rpmfnFN(rpmstrPool pool, rpmfn fndata, int ix)
268 {
269     char *fn = NULL;
270     if (ix >= 0 && ix < rpmfnFC(fndata)) {
271 	fn = rstrscat(NULL, rpmfnDN(pool, fndata, rpmfnDI(fndata, ix)),
272 			    rpmfnBN(pool, fndata, ix), NULL);
273     }
274     return fn;
275 }
276 
rpmfilesFC(rpmfiles fi)277 rpm_count_t rpmfilesFC(rpmfiles fi)
278 {
279     return (fi != NULL ? rpmfnFC(&fi->fndata) : 0);
280 }
281 
rpmfilesDC(rpmfiles fi)282 rpm_count_t rpmfilesDC(rpmfiles fi)
283 {
284     return (fi != NULL ? rpmfnDC(&fi->fndata) : 0);
285 }
286 
rpmfilesDigestAlgo(rpmfiles fi)287 int rpmfilesDigestAlgo(rpmfiles fi)
288 {
289     return (fi != NULL) ? fi->digestalgo : 0;
290 }
291 
rpmfiFC(rpmfi fi)292 rpm_count_t rpmfiFC(rpmfi fi)
293 {
294     return (fi != NULL ? rpmfilesFC(fi->files) : 0);
295 }
296 
rpmfiDC(rpmfi fi)297 rpm_count_t rpmfiDC(rpmfi fi)
298 {
299     return (fi != NULL ? rpmfilesDC(fi->files) : 0);
300 }
301 
302 #ifdef	NOTYET
rpmfiDI(rpmfi fi)303 int rpmfiDI(rpmfi fi)
304 {
305 }
306 #endif
307 
rpmfiFX(rpmfi fi)308 int rpmfiFX(rpmfi fi)
309 {
310     return (fi != NULL ? fi->i : -1);
311 }
312 
rpmfiSetFX(rpmfi fi,int fx)313 int rpmfiSetFX(rpmfi fi, int fx)
314 {
315     int i = -1;
316 
317     if (fi != NULL && fx >= 0 && fx < rpmfilesFC(fi->files)) {
318 	i = fi->i;
319 	fi->i = fx;
320 	fi->j = rpmfilesDI(fi->files, fi->i);
321     }
322     return i;
323 }
324 
rpmfiDX(rpmfi fi)325 int rpmfiDX(rpmfi fi)
326 {
327     return (fi != NULL ? fi->j : -1);
328 }
329 
rpmfiSetDX(rpmfi fi,int dx)330 int rpmfiSetDX(rpmfi fi, int dx)
331 {
332     int j = -1;
333 
334     if (fi != NULL && dx >= 0 && dx < rpmfiDC(fi)) {
335 	j = fi->j;
336 	fi->j = dx;
337     }
338     return j;
339 }
340 
rpmfilesDI(rpmfiles fi,int ix)341 int rpmfilesDI(rpmfiles fi, int ix)
342 {
343     return (fi != NULL) ? rpmfnDI(&fi->fndata, ix) : -1;
344 }
345 
rpmfilesODI(rpmfiles fi,int ix)346 int rpmfilesODI(rpmfiles fi, int ix)
347 {
348     return (fi != NULL) ? rpmfnDI(fi->ofndata, ix) : -1;
349 }
350 
rpmfilesBNId(rpmfiles fi,int ix)351 rpmsid rpmfilesBNId(rpmfiles fi, int ix)
352 {
353     return (fi != NULL) ? rpmfnBNId(&fi->fndata, ix) : 0;
354 }
355 
rpmfilesOBNId(rpmfiles fi,int ix)356 rpmsid rpmfilesOBNId(rpmfiles fi, int ix)
357 {
358     return (fi != NULL) ? rpmfnBNId(fi->ofndata, ix) : 0;
359 }
360 
rpmfilesDNId(rpmfiles fi,int jx)361 rpmsid rpmfilesDNId(rpmfiles fi, int jx)
362 {
363     return (fi != NULL) ? rpmfnDNId(&fi->fndata, jx) : 0;
364 }
365 
rpmfilesODNId(rpmfiles fi,int jx)366 rpmsid rpmfilesODNId(rpmfiles fi, int jx)
367 {
368     return (fi != NULL) ? rpmfnDNId(fi->ofndata, jx) : 0;
369 }
370 
rpmfilesBN(rpmfiles fi,int ix)371 const char * rpmfilesBN(rpmfiles fi, int ix)
372 {
373     return (fi != NULL) ? rpmfnBN(fi->pool, &fi->fndata, ix) : NULL;
374 }
375 
rpmfilesOBN(rpmfiles fi,int ix)376 const char * rpmfilesOBN(rpmfiles fi, int ix)
377 {
378     return (fi != NULL) ? rpmstrPoolStr(fi->pool, rpmfilesOBNId(fi, ix)) : NULL;
379 }
380 
rpmfilesDN(rpmfiles fi,int jx)381 const char * rpmfilesDN(rpmfiles fi, int jx)
382 {
383     return (fi != NULL) ? rpmfnDN(fi->pool, &fi->fndata, jx) : NULL;
384 }
385 
rpmfilesODN(rpmfiles fi,int jx)386 const char * rpmfilesODN(rpmfiles fi, int jx)
387 {
388     return (fi != NULL) ? rpmstrPoolStr(fi->pool, rpmfilesODNId(fi, jx)) : NULL;
389 }
390 
rpmfilesFN(rpmfiles fi,int ix)391 char * rpmfilesFN(rpmfiles fi, int ix)
392 {
393     return (fi != NULL) ? rpmfnFN(fi->pool, &fi->fndata, ix) : NULL;
394 }
395 
rpmfilesOFN(rpmfiles fi,int ix)396 char * rpmfilesOFN(rpmfiles fi, int ix)
397 {
398     return (fi != NULL) ? rpmfnFN(fi->pool, fi->ofndata, ix) : NULL;
399 }
400 
401 /* Fn is expected to be relative path, convert directory to relative too */
cmpPoolFn(rpmstrPool pool,rpmfn files,int ix,const char * fn)402 static int cmpPoolFn(rpmstrPool pool, rpmfn files, int ix, const char * fn)
403 {
404     rpmsid dnid = rpmfnDNId(files, rpmfnDI(files, ix));
405     const char *dn = rpmstrPoolStr(pool, dnid);
406     const char *reldn = (dn[0] == '/') ? dn + 1 : dn;
407     size_t l = strlen(reldn);
408     int cmp = strncmp(reldn, fn, l);
409     if (cmp == 0)
410 	cmp = strcmp(rpmfnBN(pool, files, ix), fn + l);
411     return cmp;
412 }
413 
rpmfnFindFN(rpmstrPool pool,rpmfn files,const char * fn)414 static int rpmfnFindFN(rpmstrPool pool, rpmfn files, const char * fn)
415 {
416     int fc = rpmfnFC(files);
417 
418     /*
419      * Skip payload prefix, turn absolute paths into relative. This
420      * allows handling binary rpm payloads with and without ./ prefix and
421      * srpm payloads which only contain basenames.
422      */
423     if (fn[0] == '.' && fn[1] == '/')
424 	fn += 2;
425     if (fn[0] == '/')
426 	fn += 1;
427 
428     /* try binary search */
429 
430     int lo = 0;
431     int hi = fc;
432     int mid, cmp;
433 
434     while (hi > lo) {
435 	mid = (hi + lo) / 2 ;
436 	cmp = cmpPoolFn(pool, files, mid, fn);
437 	if (cmp < 0) {
438 	    lo = mid+1;
439 	} else if (cmp > 0) {
440 	    hi = mid;
441 	} else {
442 	    return mid;
443 	}
444     }
445 
446     /* not found: try linear search */
447     for (int i=0; i < fc; i++) {
448 	if (cmpPoolFn(pool, files, i, fn) == 0)
449 	    return i;
450     }
451     return -1;
452 }
453 
rpmfilesFindFN(rpmfiles files,const char * fn)454 int rpmfilesFindFN(rpmfiles files, const char * fn)
455 {
456     return (files && fn) ? rpmfnFindFN(files->pool, &files->fndata, fn) : -1;
457 }
458 
rpmfilesFindOFN(rpmfiles files,const char * fn)459 int rpmfilesFindOFN(rpmfiles files, const char * fn)
460 {
461     return (files && fn) ? rpmfnFindFN(files->pool, files->ofndata, fn) : -1;
462 }
463 
rpmfiFindFN(rpmfi fi,const char * fn)464 int rpmfiFindFN(rpmfi fi, const char * fn)
465 {
466     int ix = -1;
467 
468     if (fi != NULL) {
469 	ix = rpmfilesFindFN(fi->files, fn);
470     }
471     return ix;
472 }
473 
rpmfiFindOFN(rpmfi fi,const char * fn)474 int rpmfiFindOFN(rpmfi fi, const char * fn)
475 {
476     int ix = -1;
477 
478     if (fi != NULL) {
479 	ix = rpmfilesFindOFN(fi->files, fn);
480     }
481     return ix;
482 }
483 
484 /*
485  * Dirnames are not sorted when separated from basenames, we need to assemble
486  * the whole path for search (binary or otherwise) purposes.
487  */
cmpPfx(rpmfiles files,int ix,const char * pfx,size_t plen)488 static int cmpPfx(rpmfiles files, int ix, const char *pfx, size_t plen)
489 {
490     char *fn = rpmfilesFN(files, ix);
491     int rc = strncmp(pfx, fn, plen);
492     free(fn);
493     return rc;
494 }
495 
rpmfilesFFlags(rpmfiles fi,int ix)496 rpmfileAttrs rpmfilesFFlags(rpmfiles fi, int ix)
497 {
498     rpmfileAttrs FFlags = 0;
499 
500     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
501 	if (fi->fflags != NULL)
502 	    FFlags = fi->fflags[ix];
503     }
504     return FFlags;
505 }
506 
rpmfilesVFlags(rpmfiles fi,int ix)507 rpmVerifyAttrs rpmfilesVFlags(rpmfiles fi, int ix)
508 {
509     rpmVerifyAttrs VFlags = 0;
510 
511     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
512 	if (fi->vflags != NULL)
513 	    VFlags = fi->vflags[ix];
514     }
515     return VFlags;
516 }
517 
rpmfilesFMode(rpmfiles fi,int ix)518 rpm_mode_t rpmfilesFMode(rpmfiles fi, int ix)
519 {
520     rpm_mode_t fmode = 0;
521 
522     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
523 	if (fi->fmodes != NULL)
524 	    fmode = fi->fmodes[ix];
525     }
526     return fmode;
527 }
528 
rpmfilesFState(rpmfiles fi,int ix)529 rpmfileState rpmfilesFState(rpmfiles fi, int ix)
530 {
531     rpmfileState fstate = RPMFILE_STATE_MISSING;
532 
533     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
534 	if (fi->fstates != NULL)
535 	    fstate = fi->fstates[ix];
536     }
537     return fstate;
538 }
539 
rpmfiDigestAlgo(rpmfi fi)540 int rpmfiDigestAlgo(rpmfi fi)
541 {
542     return fi ? rpmfilesDigestAlgo(fi->files) : 0;
543 }
544 
rpmfilesFDigest(rpmfiles fi,int ix,int * algo,size_t * len)545 const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *len)
546 {
547     const unsigned char *digest = NULL;
548 
549     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
550     	size_t diglen = rpmDigestLength(fi->digestalgo);
551 	if (fi->digests != NULL)
552 	    digest = fi->digests + (diglen * ix);
553 	if (len)
554 	    *len = diglen;
555 	if (algo)
556 	    *algo = fi->digestalgo;
557     }
558     return digest;
559 }
560 
rpmfiFDigestHex(rpmfi fi,int * algo)561 char * rpmfiFDigestHex(rpmfi fi, int *algo)
562 {
563     size_t diglen = 0;
564     char *fdigest = NULL;
565     const unsigned char *digest = rpmfiFDigest(fi, algo, &diglen);
566     if (digest) {
567 	fdigest = pgpHexStr(digest, diglen);
568     }
569     return fdigest;
570 }
571 
rpmfilesFSignature(rpmfiles fi,int ix,size_t * len)572 const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
573 {
574     const unsigned char *signature = NULL;
575 
576     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
577 	if (fi->signatures != NULL)
578 	    signature = fi->signatures + (fi->signaturelength * ix);
579 	if (len)
580 	    *len = fi->signaturelength;
581     }
582     return signature;
583 }
584 
rpmfilesFLink(rpmfiles fi,int ix)585 const char * rpmfilesFLink(rpmfiles fi, int ix)
586 {
587     const char * flink = NULL;
588 
589     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
590 	if (fi->flinks != NULL)
591 	    flink = rpmstrPoolStr(fi->pool, fi->flinks[ix]);
592     }
593     return flink;
594 }
595 
rpmfilesFSize(rpmfiles fi,int ix)596 rpm_loff_t rpmfilesFSize(rpmfiles fi, int ix)
597 {
598     rpm_loff_t fsize = 0;
599 
600     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
601 	if (fi->fsizes != NULL)
602 	    fsize = fi->fsizes[ix];
603 	else if (fi->lfsizes != NULL)
604 	    fsize = fi->lfsizes[ix];
605     }
606     return fsize;
607 }
608 
rpmfilesFRdev(rpmfiles fi,int ix)609 rpm_rdev_t rpmfilesFRdev(rpmfiles fi, int ix)
610 {
611     rpm_rdev_t frdev = 0;
612 
613     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
614 	if (fi->frdevs != NULL)
615 	    frdev = fi->frdevs[ix];
616     }
617     return frdev;
618 }
619 
rpmfilesFInode(rpmfiles fi,int ix)620 rpm_ino_t rpmfilesFInode(rpmfiles fi, int ix)
621 {
622     rpm_ino_t finode = 0;
623 
624     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
625 	if (fi->finodes != NULL)
626 	    finode = fi->finodes[ix];
627     }
628     return finode;
629 }
630 
rpmfilesColor(rpmfiles files)631 rpm_color_t rpmfilesColor(rpmfiles files)
632 {
633     rpm_color_t color = 0;
634 
635     if (files != NULL && files->fcolors != NULL) {
636 	int fc = rpmfilesFC(files);
637 	for (int i = 0; i < fc; i++)
638 	    color |= files->fcolors[i];
639 	/* XXX ignore all but lsnibble for now. */
640 	color &= 0xf;
641     }
642     return color;
643 }
644 
rpmfiColor(rpmfi fi)645 rpm_color_t rpmfiColor(rpmfi fi)
646 {
647     return (fi != NULL) ? rpmfilesColor(fi->files) : 0;
648 }
649 
rpmfilesFColor(rpmfiles fi,int ix)650 rpm_color_t rpmfilesFColor(rpmfiles fi, int ix)
651 {
652     rpm_color_t fcolor = 0;
653 
654     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
655 	if (fi->fcolors != NULL)
656 	    /* XXX ignore all but lsnibble for now. */
657 	    fcolor = (fi->fcolors[ix] & 0x0f);
658     }
659     return fcolor;
660 }
661 
rpmfilesFClass(rpmfiles fi,int ix)662 const char * rpmfilesFClass(rpmfiles fi, int ix)
663 {
664     const char * fclass = NULL;
665     int cdictx;
666 
667     if (fi != NULL && fi->fcdictx != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
668 	cdictx = fi->fcdictx[ix];
669 	if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
670 	    fclass = fi->cdict[cdictx];
671     }
672     return fclass;
673 }
674 
rpmfilesFDepends(rpmfiles fi,int ix,const uint32_t ** fddictp)675 uint32_t rpmfilesFDepends(rpmfiles fi, int ix, const uint32_t ** fddictp)
676 {
677     int fddictx = -1;
678     int fddictn = 0;
679     const uint32_t * fddict = NULL;
680 
681     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
682 	if (fi->fddictn != NULL)
683 	    fddictn = fi->fddictn[ix];
684 	if (fddictn > 0 && fi->fddictx != NULL)
685 	    fddictx = fi->fddictx[ix];
686 	if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
687 	    fddict = fi->ddict + fddictx;
688     }
689     if (fddictp)
690 	*fddictp = fddict;
691     return fddictn;
692 }
693 
rpmfilesFLinks(rpmfiles fi,int ix,const int ** files)694 uint32_t rpmfilesFLinks(rpmfiles fi, int ix, const int ** files)
695 {
696     uint32_t nlink = 0;
697 
698     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
699 	nlink = 1;
700 	if (fi->nlinks) {
701 	    struct hardlinks_s ** hardlinks = NULL;
702 	    nlinkHashGetEntry(fi->nlinks, ix, &hardlinks, NULL, NULL);
703 	    if (hardlinks) {
704 		nlink = hardlinks[0]->nlink;
705 		if (files) {
706 		    *files = hardlinks[0]->files;
707 		}
708 	    } else if (files){
709 		*files = NULL;
710 	    }
711 	}
712     }
713     return nlink;
714 }
715 
rpmfiFLinks(rpmfi fi,const int ** files)716 uint32_t rpmfiFLinks(rpmfi fi, const int ** files)
717 {
718     return rpmfilesFLinks(fi->files, fi ? fi->i : -1, files);
719 }
720 
rpmfilesFNlink(rpmfiles fi,int ix)721 uint32_t rpmfilesFNlink(rpmfiles fi, int ix)
722 {
723     return rpmfilesFLinks(fi, ix, NULL);
724 }
725 
rpmfilesFMtime(rpmfiles fi,int ix)726 rpm_time_t rpmfilesFMtime(rpmfiles fi, int ix)
727 {
728     rpm_time_t fmtime = 0;
729 
730     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
731 	if (fi->fmtimes != NULL)
732 	    fmtime = fi->fmtimes[ix];
733     }
734     return fmtime;
735 }
736 
rpmfilesFUser(rpmfiles fi,int ix)737 const char * rpmfilesFUser(rpmfiles fi, int ix)
738 {
739     const char * fuser = NULL;
740 
741     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
742 	if (fi->fuser != NULL)
743 	    fuser = rpmstrPoolStr(fi->pool, fi->fuser[ix]);
744     }
745     return fuser;
746 }
747 
rpmfilesFGroup(rpmfiles fi,int ix)748 const char * rpmfilesFGroup(rpmfiles fi, int ix)
749 {
750     const char * fgroup = NULL;
751 
752     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
753 	if (fi->fgroup != NULL)
754 	    fgroup = rpmstrPoolStr(fi->pool, fi->fgroup[ix]);
755     }
756     return fgroup;
757 }
758 
rpmfilesFCaps(rpmfiles fi,int ix)759 const char * rpmfilesFCaps(rpmfiles fi, int ix)
760 {
761     const char *fcaps = NULL;
762     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
763 	fcaps = fi->fcaps ? fi->fcaps[ix] : "";
764     }
765     return fcaps;
766 }
767 
rpmfilesFLangs(rpmfiles fi,int ix)768 const char * rpmfilesFLangs(rpmfiles fi, int ix)
769 {
770     const char *flangs = NULL;
771     if (fi != NULL && fi->flangs != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
772 	flangs = rpmstrPoolStr(fi->pool, fi->flangs[ix]);
773     }
774     return flangs;
775 }
776 
rpmfilesStat(rpmfiles fi,int ix,int flags,struct stat * sb)777 int rpmfilesStat(rpmfiles fi, int ix, int flags, struct stat *sb)
778 {
779     int rc = -1;
780     if (fi && sb) {
781 	/* XXX FIXME define proper flags with sane semantics... */
782 	int warn = flags & 0x1;
783 	const char *user = rpmfilesFUser(fi, ix);
784 	const char *group = rpmfilesFGroup(fi, ix);
785 
786 	memset(sb, 0, sizeof(*sb));
787 	sb->st_nlink = rpmfilesFLinks(fi, ix, NULL);
788 	sb->st_ino = rpmfilesFInode(fi, ix);
789 	sb->st_rdev = rpmfilesFRdev(fi, ix);
790 	sb->st_mode = rpmfilesFMode(fi, ix);
791 	sb->st_mtime = rpmfilesFMtime(fi, ix);
792 
793 	/* Only regular files and symlinks have a size */
794 	if (S_ISREG(sb->st_mode) || S_ISLNK(sb->st_mode))
795 	    sb->st_size = rpmfilesFSize(fi, ix);
796 
797 	if (user && rpmugUid(user, &sb->st_uid)) {
798 	    if (warn)
799 		rpmlog(RPMLOG_WARNING,
800 			_("user %s does not exist - using %s\n"), user, UID_0_USER);
801 	    sb->st_mode &= ~S_ISUID;	  /* turn off suid bit */
802 	}
803 
804 	if (group && rpmugGid(group, &sb->st_gid)) {
805 	    if (warn)
806 		rpmlog(RPMLOG_WARNING,
807 			_("group %s does not exist - using %s\n"), group, GID_0_GROUP);
808 	    sb->st_mode &= ~S_ISGID;	/* turn off sgid bit */
809 	}
810 
811 	rc = 0;
812     }
813     return rc;
814 }
815 
rpmfilesFps(rpmfiles fi)816 struct fingerPrint_s *rpmfilesFps(rpmfiles fi)
817 {
818     return (fi != NULL) ? fi->fps : NULL;
819 }
820 
iterFwd(rpmfi fi)821 static int iterFwd(rpmfi fi)
822 {
823     return fi->i + 1;
824 }
825 
iterBack(rpmfi fi)826 static int iterBack(rpmfi fi)
827 {
828     return fi->i - 1;
829 }
830 
iterInterval(rpmfi fi)831 static int iterInterval(rpmfi fi)
832 {
833     if (fi->i == -1)
834 	return fi->intervalStart;
835     else if (fi->i + 1 < fi->intervalEnd)
836 	return fi->i + 1;
837     else
838 	return RPMERR_ITER_END;
839 }
840 
rpmfiNext(rpmfi fi)841 int rpmfiNext(rpmfi fi)
842 {
843     int next = -1;
844     if (fi != NULL) {
845 	do {
846 	    next = fi->next(fi);
847 	} while (next == RPMERR_ITER_SKIP);
848 
849 	if (next >= 0 && next < rpmfilesFC(fi->files)) {
850 	    fi->i = next;
851 	    fi->j = rpmfilesDI(fi->files, fi->i);
852 	} else {
853 	    fi->i = -1;
854 	    if (next >= 0) {
855 		next = -1;
856 	    }
857 	}
858     }
859     return next;
860 }
861 
rpmfiInit(rpmfi fi,int fx)862 rpmfi rpmfiInit(rpmfi fi, int fx)
863 {
864     if (fi != NULL) {
865 	if (fx >= 0 && fx < rpmfilesFC(fi->files)) {
866 	    fi->i = fx - 1;
867 	    fi->j = -1;
868 	}
869     }
870 
871     return fi;
872 }
873 
rpmfiNextD(rpmfi fi)874 int rpmfiNextD(rpmfi fi)
875 {
876     int j = -1;
877 
878     if (fi != NULL && ++fi->j >= 0) {
879 	if (fi->j < rpmfilesDC(fi->files))
880 	    j = fi->j;
881 	else
882 	    fi->j = -1;
883     }
884 
885     return j;
886 }
887 
rpmfiInitD(rpmfi fi,int dx)888 rpmfi rpmfiInitD(rpmfi fi, int dx)
889 {
890     if (fi != NULL) {
891 	if (dx >= 0 && dx < rpmfilesFC(fi->files))
892 	    fi->j = dx - 1;
893 	else
894 	    fi = NULL;
895     }
896 
897     return fi;
898 }
899 
rpmfiWhatis(rpm_mode_t mode)900 rpmFileTypes rpmfiWhatis(rpm_mode_t mode)
901 {
902     if (S_ISDIR(mode))	return XDIR;
903     if (S_ISCHR(mode))	return CDEV;
904     if (S_ISBLK(mode))	return BDEV;
905     if (S_ISLNK(mode))	return LINK;
906     if (S_ISSOCK(mode))	return SOCK;
907     if (S_ISFIFO(mode))	return PIPE;
908     return REG;
909 }
910 
rpmfilesCompare(rpmfiles afi,int aix,rpmfiles bfi,int bix)911 int rpmfilesCompare(rpmfiles afi, int aix, rpmfiles bfi, int bix)
912 {
913     mode_t amode = rpmfilesFMode(afi, aix);
914     mode_t bmode = rpmfilesFMode(bfi, bix);
915     rpmFileTypes awhat = rpmfiWhatis(amode);
916 
917     if ((rpmfilesFFlags(afi, aix) & RPMFILE_GHOST) ||
918 	(rpmfilesFFlags(bfi, bix) & RPMFILE_GHOST)) return 0;
919 
920     /* Mode difference is a conflict, except for symlinks */
921     if (!(awhat == LINK && rpmfiWhatis(bmode) == LINK) && amode != bmode)
922 	return 1;
923 
924     if (awhat == LINK || awhat == REG) {
925 	if (rpmfilesFSize(afi, aix) != rpmfilesFSize(bfi, bix))
926 	    return 1;
927     }
928 
929     if (!rstreq(rpmfilesFUser(afi, aix), rpmfilesFUser(bfi, bix)))
930 	return 1;
931     if (!rstreq(rpmfilesFGroup(afi, aix), rpmfilesFGroup(bfi, bix)))
932 	return 1;
933 
934     if (awhat == LINK) {
935 	const char * alink = rpmfilesFLink(afi, aix);
936 	const char * blink = rpmfilesFLink(bfi, bix);
937 	if (alink == blink) return 0;
938 	if (alink == NULL) return 1;
939 	if (blink == NULL) return -1;
940 	return strcmp(alink, blink);
941     } else if (awhat == REG) {
942 	size_t adiglen, bdiglen;
943 	int aalgo, balgo;
944 	const unsigned char * adigest, * bdigest;
945 	adigest = rpmfilesFDigest(afi, aix, &aalgo, &adiglen);
946 	bdigest = rpmfilesFDigest(bfi, bix, &balgo, &bdiglen);
947 	if (adigest == bdigest) return 0;
948 	if (adigest == NULL) return 1;
949 	if (bdigest == NULL) return -1;
950 	/* can't meaningfully compare different hash types */
951 	if (aalgo != balgo || adiglen != bdiglen) return -1;
952 	return memcmp(adigest, bdigest, adiglen);
953     } else if (awhat == CDEV || awhat == BDEV) {
954 	if (rpmfilesFRdev(afi, aix) != rpmfilesFRdev(bfi, bix))
955 	    return 1;
956     }
957 
958     return 0;
959 }
960 
rpmfileContentsEqual(rpmfiles ofi,int oix,rpmfiles nfi,int nix)961 int rpmfileContentsEqual(rpmfiles ofi, int oix, rpmfiles nfi, int nix)
962 {
963     char * fn = rpmfilesFN(nfi, nix);
964     rpmFileTypes diskWhat, newWhat, oldWhat;
965     struct stat sb;
966     int equal = 0;
967 
968     if (fn == NULL || (lstat(fn, &sb))) {
969 	goto exit; /* The file doesn't exist on the disk */
970     }
971 
972     if (rpmfilesFSize(nfi, nix) != sb.st_size) {
973 	goto exit;
974     }
975 
976     diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
977     newWhat = rpmfiWhatis(rpmfilesFMode(nfi, nix));
978     oldWhat = rpmfiWhatis(rpmfilesFMode(ofi, oix));
979     if ((diskWhat != newWhat) || (diskWhat != oldWhat)) {
980 	goto exit;
981     }
982 
983     if (diskWhat == REG) {
984 	int oalgo, nalgo;
985 	size_t odiglen, ndiglen;
986 	const unsigned char * odigest, * ndigest;
987 	char buffer[1024];
988 
989 	odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
990 	ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
991 	/* See if the file in old pkg is identical to the one in new pkg */
992 	if ((oalgo != nalgo) || (odiglen != ndiglen) || (!ndigest) ||
993 	    (memcmp(odigest, ndigest, ndiglen) != 0)) {
994 	    goto exit;
995 	}
996 
997 	if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer) != 0) {
998 	     goto exit;		/* assume file has been removed */
999 	}
1000 
1001 	/* See if the file on disk is identical to the one in new pkg */
1002 	if (memcmp(ndigest, buffer, ndiglen) == 0) {
1003 	    equal = 1;
1004 	    goto exit;
1005 	}
1006     }  else if (diskWhat == LINK) {
1007 	const char * nFLink;
1008 	char buffer[1024];
1009 	ssize_t link_len;
1010 
1011 	nFLink = rpmfilesFLink(nfi, nix);
1012 	link_len = readlink(fn, buffer, sizeof(buffer) - 1);
1013 	if (link_len == -1) {
1014 	    goto exit;		/* assume file has been removed */
1015 	}
1016 	buffer[link_len] = '\0';
1017 	/* See if the link on disk is identical to the one in new pkg */
1018 	if (nFLink && rstreq(nFLink, buffer)) {
1019 	    equal = 1;
1020 	    goto exit;
1021 	}
1022     }
1023 
1024 exit:
1025     free(fn);
1026     return equal;
1027 }
1028 
1029 
rpmfilesDecideFate(rpmfiles ofi,int oix,rpmfiles nfi,int nix,int skipMissing)1030 rpmFileAction rpmfilesDecideFate(rpmfiles ofi, int oix,
1031 				   rpmfiles nfi, int nix,
1032 				   int skipMissing)
1033 {
1034     char * fn = rpmfilesFN(nfi, nix);
1035     rpmfileAttrs newFlags = rpmfilesFFlags(nfi, nix);
1036     char buffer[1024];
1037     rpmFileTypes dbWhat, newWhat, diskWhat;
1038     struct stat sb;
1039     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
1040     int action = FA_CREATE; /* assume we can create */
1041 
1042     /* If the new file is a ghost, leave whatever might be on disk alone. */
1043     if (newFlags & RPMFILE_GHOST) {
1044 	action = FA_SKIP;
1045 	goto exit;
1046     }
1047 
1048     if (lstat(fn, &sb)) {
1049 	/*
1050 	 * The file doesn't exist on the disk. Create it unless the new
1051 	 * package has marked it as missingok, or allfiles is requested.
1052 	 */
1053 	if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
1054 	    rpmlog(RPMLOG_DEBUG, "%s skipped due to missingok flag\n",
1055 			fn);
1056 	    action = FA_SKIP;
1057 	    goto exit;
1058 	} else {
1059 	    goto exit;
1060 	}
1061     }
1062 
1063     diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
1064     dbWhat = rpmfiWhatis(rpmfilesFMode(ofi, oix));
1065     newWhat = rpmfiWhatis(rpmfilesFMode(nfi, nix));
1066 
1067     /*
1068      * This order matters - we'd prefer to TOUCH the file if at all
1069      * possible in case something else (like the timestamp) has changed.
1070      * Only regular files and symlinks might need a backup, everything
1071      * else falls through here with FA_CREATE.
1072      */
1073     if (dbWhat == REG) {
1074 	int oalgo, nalgo;
1075 	size_t odiglen, ndiglen;
1076 	const unsigned char * odigest, * ndigest;
1077 
1078 	/* See if the file on disk is identical to the one in new pkg */
1079 	ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
1080 	if (diskWhat == REG && newWhat == REG) {
1081 	    if (rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer))
1082 		goto exit;		/* assume file has been removed */
1083 	    if (ndigest && memcmp(ndigest, buffer, ndiglen) == 0) {
1084 		action = FA_TOUCH;
1085 	        goto exit;		/* unmodified config file, touch it. */
1086 	    }
1087 	}
1088 
1089 	/* See if the file on disk is identical to the one in old pkg */
1090 	odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
1091 	if (diskWhat == REG) {
1092 	    /* hash algo changed or digest was not computed, recalculate it */
1093 	    if ((oalgo != nalgo) || (newWhat != REG)) {
1094 		if (rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer))
1095 		    goto exit;	/* assume file has been removed */
1096 		}
1097 	    if (odigest && memcmp(odigest, buffer, odiglen) == 0)
1098 	        goto exit;	/* unmodified config file, replace. */
1099 	}
1100 
1101 	/* if new file is no longer config, backup it and replace it */
1102 	if (!(newFlags & RPMFILE_CONFIG)) {
1103 	    action = FA_SAVE;
1104 	    goto exit;
1105 	}
1106 
1107 	/* If file can be determined identical in old and new pkg, let it be */
1108 	if (newWhat == REG && oalgo == nalgo && odiglen == ndiglen) {
1109 	    if (odigest && ndigest && memcmp(odigest, ndigest, odiglen) == 0) {
1110 		action = FA_SKIP; /* identical file, dont bother */
1111 		goto exit;
1112 	    }
1113 	}
1114 
1115 	/* ...but otherwise a backup will be needed */
1116 	action = save;
1117     } else if (dbWhat == LINK) {
1118 	const char * oFLink, * nFLink;
1119 
1120 	if (diskWhat == LINK) {
1121 	    /* Read link from the disk */
1122 	    ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
1123 	    if (link_len == -1)
1124 		goto exit;		/* assume file has been removed */
1125 	    buffer[link_len] = '\0';
1126 	}
1127 
1128 	/* See if the link on disk is identical to the one in new pkg */
1129 	nFLink = rpmfilesFLink(nfi, nix);
1130 	if (diskWhat == LINK && newWhat == LINK) {
1131 	    if (nFLink && rstreq(nFLink, buffer)) {
1132 		action = FA_TOUCH;
1133 		goto exit;		/* unmodified config file, touch it. */
1134 	    }
1135 	}
1136 
1137 	/* See if the link on disk is identical to the one in old pkg */
1138 	oFLink = rpmfilesFLink(ofi, oix);
1139 	if (diskWhat == LINK) {
1140 	    if (oFLink && rstreq(oFLink, buffer))
1141 		goto exit;		/* unmodified config file, replace. */
1142 	}
1143 
1144 	/* if new file is no longer config, backup it and replace it */
1145 	if (!(newFlags & RPMFILE_CONFIG)) {
1146 	    action = FA_SAVE;
1147 	    goto exit;
1148 	}
1149 
1150 	/* If link is identical in old and new pkg, let it be */
1151 	if (newWhat == LINK && oFLink && nFLink && rstreq(oFLink, nFLink)) {
1152 	    action = FA_SKIP;		/* identical file, don't bother. */
1153 	    goto exit;
1154 	}
1155 
1156 	/* ...but otherwise a backup will be needed */
1157 	action = save;
1158     }
1159 
1160 exit:
1161     free(fn);
1162     return action;
1163 }
1164 
rpmfilesConfigConflict(rpmfiles fi,int ix)1165 int rpmfilesConfigConflict(rpmfiles fi, int ix)
1166 {
1167     char * fn = NULL;
1168     rpmfileAttrs flags = rpmfilesFFlags(fi, ix);
1169     char buffer[1024];
1170     rpmFileTypes newWhat, diskWhat;
1171     struct stat sb;
1172     int rc = 0;
1173 
1174     /* Non-configs are not config conflicts. */
1175     if (!(flags & RPMFILE_CONFIG))
1176 	return 0;
1177 
1178     /* Only links and regular files can be %config, this is kinda moot */
1179     /* XXX: Why are we returning 1 here? */
1180     newWhat = rpmfiWhatis(rpmfilesFMode(fi, ix));
1181     if (newWhat != LINK && newWhat != REG)
1182 	return 1;
1183 
1184     /* If it's not on disk, there's nothing to be saved */
1185     fn = rpmfilesFN(fi, ix);
1186     if (lstat(fn, &sb))
1187 	goto exit;
1188 
1189     /*
1190      * Preserve legacy behavior: an existing %ghost %config is considered
1191      * "modified" but unlike regular %config, its never removed and
1192      * never backed up. Whether this actually makes sense is a whole
1193      * another question, but this is very long-standing behavior that
1194      * people might be depending on. The resulting FA_ALTNAME etc action
1195      * is special-cased in FSM to avoid actually creating backups on ghosts.
1196      */
1197     if (flags & RPMFILE_GHOST) {
1198 	rc = 1;
1199 	goto exit;
1200     }
1201 
1202     /* Files of different types obviously are not identical */
1203     diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
1204     if (diskWhat != newWhat) {
1205 	rc = 1;
1206 	goto exit;
1207     }
1208 
1209     /* Files of different sizes obviously are not identical */
1210     if (rpmfilesFSize(fi, ix) != sb.st_size) {
1211 	rc = 1;
1212 	goto exit;
1213     }
1214 
1215     memset(buffer, 0, sizeof(buffer));
1216     if (newWhat == REG) {
1217 	int algo;
1218 	size_t diglen;
1219 	const unsigned char *ndigest = rpmfilesFDigest(fi,ix, &algo, &diglen);
1220 	if (rpmDoDigest(algo, fn, 0, (unsigned char *)buffer))
1221 	    goto exit;	/* assume file has been removed */
1222 	if (ndigest && memcmp(ndigest, buffer, diglen) == 0)
1223 	    goto exit;	/* unmodified config file */
1224     } else /* newWhat == LINK */ {
1225 	const char * nFLink;
1226 	ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
1227 	if (link_len == -1)
1228 	    goto exit;	/* assume file has been removed */
1229 	buffer[link_len] = '\0';
1230 	nFLink = rpmfilesFLink(fi, ix);
1231 	if (nFLink && rstreq(nFLink, buffer))
1232 	    goto exit;	/* unmodified config file */
1233     }
1234 
1235     rc = 1;
1236 
1237 exit:
1238     free(fn);
1239     return rc;
1240 }
1241 
rpmfilesFree(rpmfiles fi)1242 rpmfiles rpmfilesFree(rpmfiles fi)
1243 {
1244     if (fi == NULL) return NULL;
1245 
1246     if (fi->nrefs > 1)
1247 	return rpmfilesUnlink(fi);
1248 
1249     if (rpmfilesFC(fi) > 0) {
1250 	if (fi->ofndata != &fi->fndata) {
1251 	    rpmfnClear(fi->ofndata);
1252 	    free(fi->ofndata);
1253 	}
1254 	rpmfnClear(&fi->fndata);
1255 
1256 	fi->flinks = _free(fi->flinks);
1257 	fi->flangs = _free(fi->flangs);
1258 	fi->digests = _free(fi->digests);
1259 	fi->signatures = _free(fi->signatures);
1260 	fi->fcaps = _free(fi->fcaps);
1261 
1262 	fi->cdict = _free(fi->cdict);
1263 
1264 	fi->fuser = _free(fi->fuser);
1265 	fi->fgroup = _free(fi->fgroup);
1266 
1267 	fi->fstates = _free(fi->fstates);
1268 	fi->fps = _free(fi->fps);
1269 
1270 	/* these point to header memory if KEEPHEADER is used, dont free */
1271 	if (!(fi->fiflags & RPMFI_KEEPHEADER) && fi->h == NULL) {
1272 	    fi->fmtimes = _free(fi->fmtimes);
1273 	    fi->fmodes = _free(fi->fmodes);
1274 	    fi->fflags = _free(fi->fflags);
1275 	    fi->vflags = _free(fi->vflags);
1276 	    fi->fsizes = _free(fi->fsizes);
1277 	    fi->lfsizes = _free(fi->lfsizes);
1278 	    fi->frdevs = _free(fi->frdevs);
1279 	    fi->finodes = _free(fi->finodes);
1280 
1281 	    fi->fcolors = _free(fi->fcolors);
1282 	    fi->fcdictx = _free(fi->fcdictx);
1283 	    fi->ddict = _free(fi->ddict);
1284 	    fi->fddictx = _free(fi->fddictx);
1285 	    fi->fddictn = _free(fi->fddictn);
1286 
1287 	}
1288     }
1289 
1290     fi->replacedSizes = _free(fi->replacedSizes);
1291     fi->replacedLSizes = _free(fi->replacedLSizes);
1292 
1293     fi->h = headerFree(fi->h);
1294     fi->pool = rpmstrPoolFree(fi->pool);
1295 
1296     fi->nlinks = nlinkHashFree(fi->nlinks);
1297 
1298     (void) rpmfilesUnlink(fi);
1299     memset(fi, 0, sizeof(*fi));		/* XXX trash and burn */
1300     fi = _free(fi);
1301 
1302     return NULL;
1303 }
1304 
rpmfiFree(rpmfi fi)1305 rpmfi rpmfiFree(rpmfi fi)
1306 {
1307     if (fi == NULL) return NULL;
1308 
1309     if (fi->nrefs > 1)
1310 	return rpmfiUnlink(fi);
1311 
1312     fi->files = rpmfilesFree(fi->files);
1313     fi->fn = _free(fi->fn);
1314     fi->ofn = _free(fi->ofn);
1315     fi->found = _free(fi->found);
1316     fi->archive = rpmcpioFree(fi->archive);
1317 
1318     free(fi);
1319     return NULL;
1320 }
1321 
tag2pool(rpmstrPool pool,Header h,rpmTag tag,rpm_count_t size)1322 static rpmsid * tag2pool(rpmstrPool pool, Header h, rpmTag tag, rpm_count_t size)
1323 {
1324     rpmsid *sids = NULL;
1325     struct rpmtd_s td;
1326     if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
1327 	if (rpmtdCount(&td) == size) { /* ensure right size */
1328 	    sids = rpmtdToPool(&td, pool);
1329 	}
1330 	rpmtdFreeData(&td);
1331     }
1332     return sids;
1333 }
1334 
1335 /* validate a indexed tag data triplet (such as file bn/dn/dx) */
indexSane(rpmtd xd,rpmtd yd,rpmtd zd)1336 static int indexSane(rpmtd xd, rpmtd yd, rpmtd zd)
1337 {
1338     int sane = 0;
1339     uint32_t xc = rpmtdCount(xd);
1340     uint32_t yc = rpmtdCount(yd);
1341     uint32_t zc = rpmtdCount(zd);
1342 
1343     /* check that the amount of data in each is sane */
1344     /* normally yc <= xc but larger values are not fatal (RhBug:1001553) */
1345     if (xc > 0 && yc > 0 && zc == xc) {
1346 	uint32_t * i, nvalid = 0;
1347 	/* ...and that the indexes are within bounds */
1348 	while ((i = rpmtdNextUint32(zd))) {
1349 	    if (*i >= yc)
1350 		break;
1351 	    nvalid++;
1352 	}
1353 	/* unless the loop runs to finish, the data is broken */
1354 	sane = (nvalid == zc);
1355     }
1356     return sane;
1357 }
1358 
1359 /* Get file data from header */
1360 /* Requires totalfc to be set and label err: to goto on error */
1361 #define _hgfi(_h, _tag, _td, _flags, _data) \
1362     if (headerGet((_h), (_tag), (_td), (_flags))) { \
1363 	if (rpmtdCount(_td) != totalfc) { \
1364 	    rpmlog(RPMLOG_ERR, _("Wrong number of entries for tag %s: %u found but %u expected.\n"), rpmTagGetName(_tag), rpmtdCount(_td), totalfc); \
1365 	    goto err; \
1366 	} \
1367 	if (rpmTagGetTagType(_tag) != RPM_STRING_ARRAY_TYPE && rpmTagGetTagType(_tag) != RPM_I18NSTRING_TYPE && \
1368 	    (_td)->size < totalfc * sizeof(*(_data))) {		\
1369 	    rpmlog(RPMLOG_ERR, _("Malformed data for tag %s: %u bytes found but %lu expected.\n"), rpmTagGetName(_tag), (_td)->size, totalfc * sizeof(*(_data))); \
1370 	    goto err;				\
1371 	} \
1372 	_data = ((_td)->data); \
1373     }
1374 /* Get file data from header without checking number of entries */
1375 #define _hgfinc(_h, _tag, _td, _flags, _data) \
1376     if (headerGet((_h), (_tag), (_td), (_flags))) {\
1377 	_data = ((_td)->data);	   \
1378     }
1379 
1380 /*** Hard link handling ***/
1381 
1382 struct fileid_s {
1383     rpm_dev_t id_dev;
1384     rpm_ino_t id_ino;
1385 };
1386 
1387 #undef HASHTYPE
1388 #undef HTKEYTYPE
1389 #undef HTDATATYPE
1390 #define HASHTYPE fileidHash
1391 #define HTKEYTYPE struct fileid_s
1392 #define HTDATATYPE int
1393 #include "lib/rpmhash.H"
1394 #include "lib/rpmhash.C"
1395 #undef HASHTYPE
1396 #undef HTKEYTYPE
1397 #undef HTDATATYPE
1398 
fidHashFunc(struct fileid_s a)1399 static unsigned int fidHashFunc(struct fileid_s a)
1400 {
1401     return  a.id_ino + (a.id_dev<<16) + (a.id_dev>>16);
1402 }
1403 
fidCmp(struct fileid_s a,struct fileid_s b)1404 static int fidCmp(struct fileid_s a, struct fileid_s b)
1405 {
1406     return  !((a.id_dev == b.id_dev) && (a.id_ino == b.id_ino));
1407 }
1408 
intHash(int a)1409 static unsigned int intHash(int a)
1410 {
1411     return a < 0 ? UINT_MAX-a : a;
1412 }
1413 
intCmp(int a,int b)1414 static int intCmp(int a, int b)
1415 {
1416     return a != b;
1417 }
1418 
freeNLinks(struct hardlinks_s * nlinks)1419 static struct hardlinks_s * freeNLinks(struct hardlinks_s * nlinks)
1420 {
1421     nlinks->nlink--;
1422     if (!nlinks->nlink) {
1423 	nlinks = _free(nlinks);
1424     }
1425     return nlinks;
1426 }
1427 
rpmfilesBuildNLink(rpmfiles fi,Header h)1428 static void rpmfilesBuildNLink(rpmfiles fi, Header h)
1429 {
1430     struct fileid_s f_id;
1431     fileidHash files;
1432     rpm_dev_t * fdevs = NULL;
1433     struct rpmtd_s td;
1434     int fc = 0;
1435     int totalfc = rpmfilesFC(fi);
1436 
1437     if (!fi->finodes)
1438 	return;
1439 
1440     _hgfi(h, RPMTAG_FILEDEVICES, &td, HEADERGET_ALLOC, fdevs);
1441     if (!fdevs)
1442 	return;
1443 
1444     files = fileidHashCreate(totalfc, fidHashFunc, fidCmp, NULL, NULL);
1445     for (int i=0; i < totalfc; i++) {
1446 	if (!S_ISREG(rpmfilesFMode(fi, i)) ||
1447 		(rpmfilesFFlags(fi, i) & RPMFILE_GHOST) ||
1448 		fi->finodes[i] <= 0) {
1449 	    continue;
1450 	}
1451 	fc++;
1452 	f_id.id_dev = fdevs[i];
1453 	f_id.id_ino = fi->finodes[i];
1454 	fileidHashAddEntry(files, f_id, i);
1455     }
1456     if (fileidHashNumKeys(files) != fc) {
1457 	/* Hard links */
1458 	fi->nlinks = nlinkHashCreate(2*(totalfc - fileidHashNumKeys(files)),
1459 		intHash, intCmp, NULL, freeNLinks);
1460 	for (int i=0; i < totalfc; i++) {
1461 	    int fcnt;
1462 	    int * data;
1463 	    if (!S_ISREG(rpmfilesFMode(fi, i)) ||
1464 		    (rpmfilesFFlags(fi, i) & RPMFILE_GHOST)) {
1465 		continue;
1466 	    }
1467 	    f_id.id_dev = fdevs[i];
1468 	    f_id.id_ino = fi->finodes[i];
1469 	    fileidHashGetEntry(files, f_id, &data, &fcnt, NULL);
1470 	    if (fcnt > 1 && !nlinkHashHasEntry(fi->nlinks, i)) {
1471 		struct hardlinks_s * hlinks;
1472 		hlinks = xmalloc(sizeof(struct hardlinks_s)+
1473 			fcnt*sizeof(hlinks->files[0]));
1474 		hlinks->nlink = fcnt;
1475 		for (int j=0; j<fcnt; j++) {
1476 		    hlinks->files[j] = data[j];
1477 		    nlinkHashAddEntry(fi->nlinks, data[j], hlinks);
1478 		}
1479 	    }
1480 	}
1481     }
1482     _free(fdevs);
1483     files = fileidHashFree(files);
1484 err:
1485     return;
1486 }
1487 
1488 /* Convert a tag of hex strings to binary presentation */
hex2bin(Header h,rpmTagVal tag,rpm_count_t num,size_t len)1489 static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
1490 {
1491     struct rpmtd_s td;
1492     uint8_t *bin = NULL;
1493 
1494     if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
1495 	uint8_t *t = bin = xmalloc(num * len);
1496 	const char *s;
1497 
1498 	while ((s = rpmtdNextString(&td))) {
1499 	    if (*s == '\0') {
1500 		memset(t, 0, len);
1501 		t += len;
1502 		continue;
1503 	    }
1504 	    for (int j = 0; j < len; j++, t++, s += 2)
1505 		*t = (rnibble(s[0]) << 4) | rnibble(s[1]);
1506 	}
1507     }
1508     rpmtdFreeData(&td);
1509 
1510     return bin;
1511 }
1512 
rpmfilesPopulate(rpmfiles fi,Header h,rpmfiFlags flags)1513 static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
1514 {
1515     headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ?
1516 				HEADERGET_MINMEM : HEADERGET_ALLOC;
1517     headerGetFlags defFlags = HEADERGET_ALLOC;
1518     struct rpmtd_s digalgo, td;
1519     rpm_count_t totalfc = rpmfilesFC(fi);
1520 
1521     /* XXX TODO: all these should be sanity checked, ugh... */
1522     if (!(flags & RPMFI_NOFILEMODES))
1523 	_hgfi(h, RPMTAG_FILEMODES, &td, scareFlags, fi->fmodes);
1524     if (!(flags & RPMFI_NOFILEFLAGS))
1525 	_hgfi(h, RPMTAG_FILEFLAGS, &td, scareFlags, fi->fflags);
1526     if (!(flags & RPMFI_NOFILEVERIFYFLAGS))
1527 	_hgfi(h, RPMTAG_FILEVERIFYFLAGS, &td, scareFlags, fi->vflags);
1528     if (!(flags & RPMFI_NOFILESIZES)) {
1529 	_hgfi(h, RPMTAG_FILESIZES, &td, scareFlags, fi->fsizes);
1530 	_hgfi(h, RPMTAG_LONGFILESIZES, &td, scareFlags, fi->lfsizes);
1531     }
1532     if (!(flags & RPMFI_NOFILECOLORS))
1533 	_hgfi(h, RPMTAG_FILECOLORS, &td, scareFlags, fi->fcolors);
1534 
1535     if (!(flags & RPMFI_NOFILECLASS)) {
1536 	_hgfinc(h, RPMTAG_CLASSDICT, &td, scareFlags, fi->cdict);
1537 	fi->ncdict = rpmtdCount(&td);
1538 	_hgfi(h, RPMTAG_FILECLASS, &td, scareFlags, fi->fcdictx);
1539     }
1540     if (!(flags & RPMFI_NOFILEDEPS)) {
1541 	_hgfinc(h, RPMTAG_DEPENDSDICT, &td, scareFlags, fi->ddict);
1542 	fi->nddict = rpmtdCount(&td);
1543 	_hgfinc(h, RPMTAG_FILEDEPENDSX, &td, scareFlags, fi->fddictx);
1544 	_hgfinc(h, RPMTAG_FILEDEPENDSN, &td, scareFlags, fi->fddictn);
1545     }
1546 
1547     if (!(flags & RPMFI_NOFILESTATES))
1548 	_hgfi(h, RPMTAG_FILESTATES, &td, defFlags, fi->fstates);
1549 
1550     if (!(flags & RPMFI_NOFILECAPS))
1551 	_hgfi(h, RPMTAG_FILECAPS, &td, defFlags, fi->fcaps);
1552 
1553     if (!(flags & RPMFI_NOFILELINKTOS))
1554 	fi->flinks = tag2pool(fi->pool, h, RPMTAG_FILELINKTOS, totalfc);
1555     /* FILELANGS are only interesting when installing */
1556     if ((headerGetInstance(h) == 0) && !(flags & RPMFI_NOFILELANGS))
1557 	fi->flangs = tag2pool(fi->pool, h, RPMTAG_FILELANGS, totalfc);
1558 
1559     /* See if the package has non-md5 file digests */
1560     fi->digestalgo = PGPHASHALGO_MD5;
1561     if (headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM)) {
1562 	uint32_t *algo = rpmtdGetUint32(&digalgo);
1563 	/* Hmm, what to do with unknown digest algorithms? */
1564 	if (algo && rpmDigestLength(*algo) != 0) {
1565 	    fi->digestalgo = *algo;
1566 	}
1567     }
1568 
1569     fi->digests = NULL;
1570     /* grab hex digests from header and store in binary format */
1571     if (!(flags & RPMFI_NOFILEDIGESTS)) {
1572 	size_t diglen = rpmDigestLength(fi->digestalgo);
1573 	fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen);
1574     }
1575 
1576     fi->signatures = NULL;
1577     /* grab hex signatures from header and store in binary format */
1578     if (!(flags & RPMFI_NOFILESIGNATURES)) {
1579 	fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
1580 	fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
1581 				 totalfc, fi->signaturelength);
1582     }
1583 
1584     /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
1585     if (!(flags & RPMFI_NOFILEMTIMES))
1586 	_hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
1587     if (!(flags & RPMFI_NOFILERDEVS))
1588 	_hgfi(h, RPMTAG_FILERDEVS, &td, scareFlags, fi->frdevs);
1589     if (!(flags & RPMFI_NOFILEINODES)) {
1590 	_hgfi(h, RPMTAG_FILEINODES, &td, scareFlags, fi->finodes);
1591 	rpmfilesBuildNLink(fi, h);
1592     }
1593     if (!(flags & RPMFI_NOFILEUSER)) {
1594 	fi->fuser = tag2pool(fi->pool, h, RPMTAG_FILEUSERNAME, totalfc);
1595 	if (!fi->fuser) goto err;
1596     }
1597     if (!(flags & RPMFI_NOFILEGROUP)) {
1598 	fi->fgroup = tag2pool(fi->pool, h, RPMTAG_FILEGROUPNAME, totalfc);
1599 	if (!fi->fgroup) goto err;
1600     }
1601     /* TODO: validate and return a real error */
1602     return 0;
1603  err:
1604     return -1;
1605 }
1606 
rpmfilesNew(rpmstrPool pool,Header h,rpmTagVal tagN,rpmfiFlags flags)1607 rpmfiles rpmfilesNew(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
1608 {
1609     rpmfiles fi = xcalloc(1, sizeof(*fi));
1610     int fc;
1611 
1612     fi->magic = RPMFIMAGIC;
1613     fi->fiflags = flags;
1614     /* private or shared pool? */
1615     fi->pool = (pool != NULL) ? rpmstrPoolLink(pool) : rpmstrPoolCreate();
1616 
1617     /*
1618      * Grab and validate file triplet data. Headers with no files simply
1619      * fall through here and an empty file set is returned.
1620      */
1621     fc = rpmfnInit(&fi->fndata, RPMTAG_BASENAMES, h, fi->pool);
1622 
1623     /* Broken data, bail out */
1624     if (fc < 0)
1625 	goto err;
1626 
1627     /* populate the rest of the stuff if we have files */
1628     if (fc > 0) {
1629 	if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
1630 	    /* For relocated packages, grab the original paths too */
1631 	    int ofc;
1632 	    fi->ofndata = xmalloc(sizeof(*fi->ofndata));
1633 	    ofc = rpmfnInit(fi->ofndata, RPMTAG_ORIGBASENAMES, h, fi->pool);
1634 
1635 	    if (ofc != 0 && ofc != fc)
1636 		goto err;
1637 	} else {
1638 	    /* In the normal case, orig is the same as actual path data */
1639 	    fi->ofndata = &fi->fndata;
1640 	}
1641 
1642 	if (rpmfilesPopulate(fi, h, flags))
1643 	    goto err;
1644     }
1645 
1646     /* freeze the pool to save memory, but only if private pool */
1647     if (fi->pool != pool)
1648 	rpmstrPoolFreeze(fi->pool, 0);
1649 
1650     fi->h = (fi->fiflags & RPMFI_KEEPHEADER) ? headerLink(h) : NULL;
1651 
1652     return rpmfilesLink(fi);
1653 
1654 err:
1655     rpmfilesFree(fi);
1656     return NULL;
1657 }
1658 
1659 static int iterWriteArchiveNext(rpmfi fi);
1660 static int iterReadArchiveNext(rpmfi fi);
1661 static int iterReadArchiveNextContentFirst(rpmfi fi);
1662 static int iterReadArchiveNextOmitHardlinks(rpmfi fi);
1663 
1664 static int (*nextfuncs[])(rpmfi fi) = {
1665     iterFwd,
1666     iterBack,
1667     iterWriteArchiveNext,
1668     iterReadArchiveNext,
1669     iterReadArchiveNextContentFirst,
1670     iterReadArchiveNextOmitHardlinks,
1671     iterInterval,
1672 };
1673 
1674 
initIter(rpmfiles files,int itype,int link)1675 static rpmfi initIter(rpmfiles files, int itype, int link)
1676 {
1677     rpmfi fi = NULL;
1678 
1679     if (files && itype>=0 && itype<=RPMFILEITERMAX) {
1680 	fi = xcalloc(1, sizeof(*fi));
1681 	fi->i = -1;
1682 	fi->files = link ? rpmfilesLink(files) : files;
1683 	fi->next = nextfuncs[itype];
1684 	fi->i = -1;
1685 	if (itype == RPMFI_ITER_BACK) {
1686 	    fi->i = rpmfilesFC(fi->files);
1687 	} else if (itype >=RPMFI_ITER_READ_ARCHIVE
1688 	    && itype <= RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS) {
1689 
1690 	    fi->found = xcalloc(1, (rpmfiFC(fi)>>3) + 1);
1691 	}
1692 	rpmfiLink(fi);
1693     }
1694     return fi;
1695 }
1696 
rpmfilesIter(rpmfiles files,int itype)1697 rpmfi rpmfilesIter(rpmfiles files, int itype)
1698 {
1699     /* standalone iterators need to bump our refcount */
1700     return initIter(files, itype, 1);
1701 }
1702 
rpmfilesFindPrefix(rpmfiles fi,const char * pfx)1703 rpmfi rpmfilesFindPrefix(rpmfiles fi, const char *pfx)
1704 {
1705     int l, u, c, comparison;
1706     rpmfi iterator = NULL;
1707 
1708     if (!fi || !pfx)
1709 	return NULL;
1710 
1711     size_t plen = strlen(pfx);
1712     l = 0;
1713     u = rpmfilesFC(fi);
1714     while (l < u) {
1715 	c = (l + u) / 2;
1716 
1717 	comparison = cmpPfx(fi, c, pfx, plen);
1718 
1719 	if (comparison < 0)
1720 	    u = c;
1721 	else if (comparison > 0)
1722 	    l = c + 1;
1723 	else {
1724 	    if (cmpPfx(fi, l, pfx, plen))
1725 		l = c;
1726 	    while (l > 0 && !cmpPfx(fi, l - 1, pfx, plen))
1727 		l--;
1728 	    if ( u >= rpmfilesFC(fi) || cmpPfx(fi, u, pfx, plen))
1729 		u = c;
1730 	    while (++u < rpmfilesFC(fi)) {
1731 		if (cmpPfx(fi, u, pfx, plen))
1732 		    break;
1733 	    }
1734 	    break;
1735 	}
1736 
1737     }
1738 
1739     if (l < u) {
1740 	iterator = initIter(fi, RPMFI_ITER_INTERVAL, 1);
1741 	iterator->intervalStart = l;
1742 	iterator->intervalEnd = u;
1743     }
1744 
1745     return iterator;
1746 }
1747 
rpmfiNewPool(rpmstrPool pool,Header h,rpmTagVal tagN,rpmfiFlags flags)1748 rpmfi rpmfiNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
1749 {
1750     rpmfiles files = rpmfilesNew(pool, h, tagN, flags);
1751     /* we already own rpmfiles, avoid extra refcount on it */
1752     return initIter(files, RPMFI_ITER_FWD, 0);
1753 }
1754 
rpmfiNew(const rpmts ts,Header h,rpmTagVal tagN,rpmfiFlags flags)1755 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTagVal tagN, rpmfiFlags flags)
1756 {
1757     return rpmfiNewPool(NULL, h, tagN, flags);
1758 }
1759 
rpmfilesSetFReplacedSize(rpmfiles fi,int ix,rpm_loff_t newsize)1760 void rpmfilesSetFReplacedSize(rpmfiles fi, int ix, rpm_loff_t newsize)
1761 {
1762     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
1763 	/* Switch over to 64 bit variant */
1764 	int fc = rpmfilesFC(fi);
1765 	if (newsize > UINT32_MAX && fi->replacedLSizes == NULL) {
1766 	    fi->replacedLSizes = xcalloc(fc, sizeof(*fi->replacedLSizes));
1767 	    /* copy 32 bit data */
1768 	    if (fi->replacedSizes) {
1769 		for (int i=0; i < fc; i++)
1770 		    fi->replacedLSizes[i] = fi->replacedSizes[i];
1771 		fi->replacedSizes = _free(fi->replacedSizes);
1772 	    }
1773 	}
1774 	if (fi->replacedLSizes != NULL) {
1775 	    fi->replacedLSizes[ix] = newsize;
1776 	} else {
1777 	    if (fi->replacedSizes == NULL)
1778 		fi->replacedSizes = xcalloc(fc, sizeof(*fi->replacedSizes));
1779 	    fi->replacedSizes[ix] = (rpm_off_t) newsize;
1780 	}
1781     }
1782 }
1783 
rpmfilesFReplacedSize(rpmfiles fi,int ix)1784 rpm_loff_t rpmfilesFReplacedSize(rpmfiles fi, int ix)
1785 {
1786     rpm_loff_t rsize = 0;
1787     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
1788 	if (fi->replacedSizes) {
1789 	    rsize = fi->replacedSizes[ix];
1790 	} else if (fi->replacedLSizes) {
1791 	    rsize = fi->replacedLSizes[ix];
1792 	}
1793     }
1794     return rsize;
1795 }
1796 
rpmfilesFpLookup(rpmfiles fi,fingerPrintCache fpc)1797 void rpmfilesFpLookup(rpmfiles fi, fingerPrintCache fpc)
1798 {
1799     /* This can get called twice (eg yum), scratch former results and redo */
1800     if (rpmfilesFC(fi) > 0) {
1801 	rpmfn fn = &fi->fndata;
1802 	if (fi->fps)
1803 	    free(fi->fps);
1804 	fi->fps = fpLookupList(fpc, fi->pool,
1805 			       fn->dnid, fn->bnid, fn->dil, fn->fc);
1806     }
1807 }
1808 
1809 /*
1810  * Generate iterator accessors function wrappers, these do nothing but
1811  * call the corresponding rpmfiFooIndex(fi, fi->[ij])
1812  */
1813 
1814 #define RPMFI_ITERFUNC(TYPE, NAME, IXV) \
1815     TYPE rpmfi ## NAME(rpmfi fi) { return rpmfiles ## NAME(fi ? fi->files : NULL, fi ? fi->IXV : -1); }
1816 
RPMFI_ITERFUNC(rpmsid,BNId,i)1817 RPMFI_ITERFUNC(rpmsid, BNId, i)
1818 RPMFI_ITERFUNC(rpmsid, DNId, j)
1819 RPMFI_ITERFUNC(const char *, BN, i)
1820 RPMFI_ITERFUNC(const char *, DN, j)
1821 RPMFI_ITERFUNC(const char *, OBN, i)
1822 RPMFI_ITERFUNC(const char *, ODN, j)
1823 RPMFI_ITERFUNC(const char *, FLink, i)
1824 RPMFI_ITERFUNC(const char *, FUser, i)
1825 RPMFI_ITERFUNC(const char *, FGroup, i)
1826 RPMFI_ITERFUNC(const char *, FCaps, i)
1827 RPMFI_ITERFUNC(const char *, FLangs, i)
1828 RPMFI_ITERFUNC(const char *, FClass, i)
1829 RPMFI_ITERFUNC(rpmfileState, FState, i)
1830 RPMFI_ITERFUNC(rpmfileAttrs, FFlags, i)
1831 RPMFI_ITERFUNC(rpmVerifyAttrs, VFlags, i)
1832 RPMFI_ITERFUNC(rpm_mode_t, FMode, i)
1833 RPMFI_ITERFUNC(rpm_rdev_t, FRdev, i)
1834 RPMFI_ITERFUNC(rpm_time_t, FMtime, i)
1835 RPMFI_ITERFUNC(rpm_ino_t, FInode, i)
1836 RPMFI_ITERFUNC(rpm_loff_t, FSize, i)
1837 RPMFI_ITERFUNC(rpm_color_t, FColor, i)
1838 RPMFI_ITERFUNC(uint32_t, FNlink, i)
1839 
1840 const char * rpmfiFN(rpmfi fi)
1841 {
1842     const char *fn = ""; /* preserve behavior on errors */
1843     if (fi != NULL) {
1844 	free(fi->fn);
1845 	fi->fn = rpmfilesFN(fi->files, fi->i);
1846 	if (fi->fn != NULL)
1847 	    fn = fi->fn;
1848     }
1849     return fn;
1850 }
1851 
rpmfiOFN(rpmfi fi)1852 const char * rpmfiOFN(rpmfi fi)
1853 {
1854     const char *fn = ""; /* preserve behavior on errors */
1855     if (fi != NULL) {
1856 	free(fi->ofn);
1857 	fi->ofn = rpmfilesOFN(fi->files, fi->i);
1858 	if (fi->ofn != NULL)
1859 	    fn = fi->ofn;
1860     }
1861     return fn;
1862 }
1863 
rpmfiFDigest(rpmfi fi,int * algo,size_t * len)1864 const unsigned char * rpmfiFDigest(rpmfi fi, int *algo, size_t *len)
1865 {
1866     return rpmfilesFDigest(fi->files, fi ? fi->i : -1, algo, len);
1867 }
1868 
rpmfiFSignature(rpmfi fi,size_t * len)1869 const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
1870 {
1871     return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
1872 }
1873 
rpmfiFDepends(rpmfi fi,const uint32_t ** fddictp)1874 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
1875 {
1876     return rpmfilesFDepends(fi->files,  fi ? fi->i : -1, fddictp);
1877 }
1878 
rpmfiStat(rpmfi fi,int flags,struct stat * sb)1879 int rpmfiStat(rpmfi fi, int flags, struct stat *sb)
1880 {
1881     int rc = -1;
1882     if (fi != NULL) {
1883 	rc = rpmfilesStat(fi->files, fi->i, flags, sb);
1884 	/* In archives, hardlinked files are empty except for the last one */
1885 	if (rc == 0 && fi->archive && sb->st_nlink > 1) {
1886 	    const int *links = NULL;
1887 	    if (rpmfiFLinks(fi, &links) && links[sb->st_nlink-1] != fi->i)
1888 		sb->st_size = 0;
1889 	}
1890     }
1891     return rc;
1892 }
1893 
rpmfiCompare(const rpmfi afi,const rpmfi bfi)1894 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
1895 {
1896     return rpmfilesCompare(afi->files, afi ? afi->i : -1, bfi->files, bfi ? bfi->i : -1);
1897 }
1898 
rpmfiVerify(rpmfi fi,rpmVerifyAttrs omitMask)1899 rpmVerifyAttrs rpmfiVerify(rpmfi fi, rpmVerifyAttrs omitMask)
1900 {
1901     return rpmfilesVerify(fi->files, fi->i, omitMask);
1902 }
1903 
rpmfilesPool(rpmfiles fi)1904 rpmstrPool rpmfilesPool(rpmfiles fi)
1905 {
1906     return (fi != NULL) ? fi->pool : NULL;
1907 }
1908 
rpmfiFiles(rpmfi fi)1909 rpmfiles rpmfiFiles(rpmfi fi)
1910 {
1911     return (fi != NULL) ? fi->files : NULL;
1912 }
1913 
1914 /******************************************************/
1915 /*** Archive handling *********************************/
1916 /******************************************************/
1917 
rpmfiNewArchiveReader(FD_t fd,rpmfiles files,int itype)1918 rpmfi rpmfiNewArchiveReader(FD_t fd, rpmfiles files, int itype)
1919 {
1920     rpmcpio_t archive = rpmcpioOpen(fd, O_RDONLY);
1921     rpmfi fi = NULL;
1922     if (archive && itype >= RPMFI_ITER_READ_ARCHIVE) {
1923 	fi = rpmfilesIter(files, itype);
1924     }
1925     if (fi) {
1926 	fi->archive = archive;
1927     } else {
1928 	rpmcpioFree(archive);
1929     }
1930     return fi;
1931 }
1932 
rpmfiNewArchiveWriter(FD_t fd,rpmfiles files)1933 rpmfi rpmfiNewArchiveWriter(FD_t fd, rpmfiles files)
1934 {
1935     rpmcpio_t archive = rpmcpioOpen(fd, O_WRONLY);
1936     rpmfi fi = NULL;
1937     if (archive) {
1938 	fi = rpmfilesIter(files, RPMFI_ITER_WRITE_ARCHIVE);
1939     }
1940     if (fi) {
1941 	fi->archive = archive;
1942     } else {
1943 	rpmcpioFree(archive);
1944     }
1945     return fi;
1946 }
1947 
rpmfiArchiveClose(rpmfi fi)1948 int rpmfiArchiveClose(rpmfi fi)
1949 {
1950     if (fi == NULL)
1951 	return -1;
1952     int rc = rpmcpioClose(fi->archive);
1953     return rc;
1954 }
1955 
rpmfiArchiveTell(rpmfi fi)1956 rpm_loff_t rpmfiArchiveTell(rpmfi fi)
1957 {
1958     if (fi == NULL || fi->archive == NULL)
1959 	return 0;
1960     return (rpm_loff_t) rpmcpioTell(fi->archive);
1961 }
1962 
rpmfiArchiveWriteHeader(rpmfi fi)1963 static int rpmfiArchiveWriteHeader(rpmfi fi)
1964 {
1965     int rc;
1966     struct stat st;
1967 
1968     if (rpmfiStat(fi, 0, &st))
1969 	return -1;
1970 
1971     rpmfiles files = fi->files;
1972 
1973     if (files->lfsizes) {
1974 	return rpmcpioStrippedHeaderWrite(fi->archive, rpmfiFX(fi), st.st_size);
1975     } else {
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);
1980 	free(path);
1981     }
1982 
1983     return rc;
1984 }
1985 
iterWriteArchiveNextFile(rpmfi fi)1986 static int iterWriteArchiveNextFile(rpmfi fi)
1987 {
1988     rpmfiles files = rpmfiFiles(fi);
1989     int fx = rpmfiFX(fi);
1990     int fc = rpmfiFC(fi);
1991     const int * hardlinks;
1992     int numHardlinks = 0;
1993 
1994     /* already processing hard linked files */
1995     if (rpmfiFNlink(fi) > 1) {
1996 	/* search next hard linked file */
1997 	fi->i = -1;
1998 	for (int i=fx+1; i<fc; i++) {
1999 	    /* no ghosts */
2000 	    if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
2001 		continue;
2002 	    numHardlinks = rpmfilesFLinks(files, i, &hardlinks);
2003 	    if (numHardlinks > 1 && hardlinks[0] == i) {
2004 		rpmfiSetFX(fi, i);
2005 		break;
2006 	    }
2007 	}
2008     } else {
2009 	fi->i = -1;
2010 	/* search next non hardlinked file */
2011 	for (int i=fx+1; i<fc; i++) {
2012 	    /* no ghosts */
2013 	    if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
2014 		continue;
2015 	    if (rpmfilesFNlink(files, i) < 2) {
2016 		rpmfiSetFX(fi, i);
2017 		break;
2018 	    }
2019 	}
2020 	if (rpmfiFX(fi) == -1) {
2021 	    /* continue with first hard linked file */
2022 	    for (int i=0; i<fc; i++) {
2023 		/* no ghosts */
2024 		if (rpmfilesFFlags(files, i) & RPMFILE_GHOST)
2025 		    continue;
2026 		numHardlinks = rpmfilesFLinks(files, i, &hardlinks);
2027 		if (numHardlinks > 1) {
2028 		    rpmfiSetFX(fi, i);
2029 		    break;
2030 		}
2031 	    }
2032 	}
2033     }
2034     if (rpmfiFX(fi) == -1)
2035 	return -1;
2036 
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);
2042 	    if (rc) {
2043 		return rc;
2044 	    }
2045 	}
2046 	rpmfiSetFX(fi, hardlinks[0]);
2047     } else {
2048 	int rc = rpmfiArchiveWriteHeader(fi);
2049 	if (rc) {
2050 	    return rc;
2051 	}
2052     }
2053     return rpmfiFX(fi);
2054 }
2055 
iterWriteArchiveNext(rpmfi fi)2056 static int iterWriteArchiveNext(rpmfi fi)
2057 {
2058     int fx;
2059     /* loop over the files we can handle ourself */
2060     do {
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;
2068 	    }
2069 	} else if (S_ISREG(rpmfiFMode(fi)) && rpmfiFSize(fi)) {
2070 	    /* this file actually needs some content */
2071 	    return fx;
2072 	}
2073 	/* go on for special files, directories and empty files */
2074     } while (fx >= 0);
2075     return fx;
2076 }
2077 
rpmfiArchiveWrite(rpmfi fi,const void * buf,size_t size)2078 size_t rpmfiArchiveWrite(rpmfi fi, const void * buf, size_t size)
2079 {
2080     if (fi == NULL || fi->archive == NULL)
2081 	return -1;
2082     return rpmcpioWrite(fi->archive, buf, size);
2083 }
2084 
rpmfiArchiveWriteFile(rpmfi fi,FD_t fd)2085 int rpmfiArchiveWriteFile(rpmfi fi, FD_t fd)
2086 {
2087     rpm_loff_t left;
2088     int rc = 0;
2089     size_t len;
2090     char buf[BUFSIZ*4];
2091 
2092     if (fi == NULL || fi->archive == NULL || fd == NULL)
2093 	return -1;
2094 
2095     left = rpmfiFSize(fi);
2096 
2097     while (left) {
2098 	len = (left > sizeof(buf) ? sizeof(buf) : left);
2099 	if (Fread(buf, sizeof(*buf), len, fd) != len || Ferror(fd)) {
2100 	    rc = RPMERR_READ_FAILED;
2101 	    break;
2102 	}
2103 
2104 	if (rpmcpioWrite(fi->archive, buf, len) != len) {
2105 	    rc = RPMERR_WRITE_FAILED;
2106 	    break;
2107 	}
2108 	left -= len;
2109     }
2110     return rc;
2111 }
2112 
rpmfiSetFound(rpmfi fi,int ix)2113 static void rpmfiSetFound(rpmfi fi, int ix)
2114 {
2115     fi->found[ix >> 3] |= (1 << (ix % 8));
2116 }
2117 
rpmfiFound(rpmfi fi,int ix)2118 static int rpmfiFound(rpmfi fi, int ix)
2119 {
2120     return fi->found[ix >> 3] & (1 << (ix % 8));
2121 }
2122 
iterReadArchiveNext(rpmfi fi)2123 static int iterReadArchiveNext(rpmfi fi)
2124 {
2125     int rc;
2126     int fx = -1;
2127     int fc = rpmfilesFC(fi->files);
2128     char * path = NULL;
2129 
2130     if (fi->archive == NULL)
2131 	return -1;
2132 
2133     /* Read next payload header. */
2134     rc = rpmcpioHeaderRead(fi->archive, &path, &fx);
2135 
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;
2142 		break;
2143             }
2144 	}
2145     }
2146     if (rc) {
2147 	return rc;
2148     }
2149 
2150     if (path) {
2151 	/* Regular cpio archive, identify mapping index. */
2152 	fx = rpmfilesFindOFN(fi->files, path);
2153 	free(path);
2154     }
2155 
2156     if (fx >= 0 && fx < fc) {
2157 	rpm_loff_t fsize = 0;
2158 	rpm_mode_t mode = rpmfilesFMode(fi->files, fx);
2159 
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;
2163 
2164 	if (S_ISREG(mode)) {
2165 	    const int * links;
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? */
2176 	    free(buf);
2177 	}
2178 	rpmcpioSetExpectedFileSize(fi->archive, fsize);
2179 	rpmfiSetFound(fi, fx);
2180     } else {
2181 	/* Mapping error */
2182 	rc = RPMERR_UNMAPPED_FILE;
2183     }
2184     return (rc != 0) ? rc : fx;
2185 }
2186 
2187 
iterReadArchiveNextOmitHardlinks(rpmfi fi)2188 static int iterReadArchiveNextOmitHardlinks(rpmfi fi)
2189 {
2190     int fx;
2191     const int * links;
2192     int nlink;
2193     do {
2194 	fx = iterReadArchiveNext(fi);
2195 	nlink = rpmfilesFLinks(fi->files, fx, &links);
2196     } while (fx>=0 && nlink>1 && links[nlink-1]!=fx);
2197     return fx;
2198 }
2199 
iterReadArchiveNextContentFirst(rpmfi fi)2200 static int iterReadArchiveNextContentFirst(rpmfi fi)
2201 {
2202     int fx = rpmfiFX(fi);
2203     const int * links;
2204     int nlink;
2205     /* decide what to do on the basis of the last entry */
2206     nlink = rpmfilesFLinks(fi->files, fx, &links);
2207     if (nlink > 1) {
2208 	/* currently reading through hard links */
2209 	if (fx == links[nlink-1]) {
2210 	    /* arrived back at last entry, read on */
2211 	    fx = iterReadArchiveNext(fi);
2212 	} else {
2213 	    /* next hard link */
2214 	    /* scales poorly but shouldn't matter */
2215 	    for (int i=0; i<nlink; i++) {
2216 		if (links[i] == fx) {
2217 		    fx = links[i+1];
2218 		    return fx;
2219 		}
2220 	    }
2221 	    /* should never happen */
2222 	    return -1;
2223 	}
2224     } else {
2225 	fx = iterReadArchiveNext(fi);
2226     }
2227 
2228     /* look at the new entry */
2229     nlink = rpmfilesFLinks(fi->files, fx, &links);
2230     /* arrived at new set of hardlinks? */
2231     if (nlink > 1) {
2232 	/* read over all entries to the last one (containing the content) */
2233 	do {
2234 	    fx = iterReadArchiveNext(fi);
2235 	} while (fx >=0 && fx != links[nlink-1]);
2236 	/* rewind to the first entry */
2237 	if (fx >= 0) {
2238 	    fx = links[0];
2239 	}
2240     }
2241     return fx;
2242 }
2243 
rpmfiArchiveHasContent(rpmfi fi)2244 int rpmfiArchiveHasContent(rpmfi fi)
2245 {
2246     int res = 0;
2247     if (fi && S_ISREG(rpmfiFMode(fi))) {
2248 	const int * links;
2249 	int nlink = rpmfiFLinks(fi, &links);
2250 	if (nlink > 1) {
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];
2256 	    }
2257 	} else {
2258 	    res = 1;
2259 	}
2260     }
2261     return res;
2262 }
2263 
rpmfiArchiveRead(rpmfi fi,void * buf,size_t size)2264 ssize_t rpmfiArchiveRead(rpmfi fi, void * buf, size_t size)
2265 {
2266     if (fi == NULL || fi->archive == NULL)
2267 	return -1;
2268     return rpmcpioRead(fi->archive, buf, size);
2269 }
2270 
rpmfiArchiveReadToFilePsm(rpmfi fi,FD_t fd,int nodigest,rpmpsm psm)2271 int rpmfiArchiveReadToFilePsm(rpmfi fi, FD_t fd, int nodigest, rpmpsm psm)
2272 {
2273     if (fi == NULL || fi->archive == NULL || fd == NULL)
2274 	return -1;
2275 
2276     rpm_loff_t left = rpmfiFSize(fi);
2277     const unsigned char * fidigest = NULL;
2278     pgpHashAlgo digestalgo = 0;
2279     int rc = 0;
2280     char buf[BUFSIZ*4];
2281 
2282     if (!nodigest) {
2283 	digestalgo = rpmfiDigestAlgo(fi);
2284 	fidigest = rpmfilesFDigest(fi->files, rpmfiFX(fi), NULL, NULL);
2285 	fdInitDigest(fd, digestalgo, 0);
2286     }
2287 
2288     while (left) {
2289 	size_t len;
2290 	len = (left > sizeof(buf) ? sizeof(buf) : left);
2291 	if (rpmcpioRead(fi->archive, buf, len) != len) {
2292 	    rc = RPMERR_READ_FAILED;
2293 	    goto exit;
2294 	}
2295 	if ((Fwrite(buf, sizeof(*buf), len, fd) != len) || Ferror(fd)) {
2296 	    rc = RPMERR_WRITE_FAILED;
2297 	    goto exit;
2298 	}
2299 
2300 	rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
2301 	left -= len;
2302     }
2303 
2304     if (!nodigest) {
2305 	void * digest = NULL;
2306 
2307 	(void) Fflush(fd);
2308 	fdFiniDigest(fd, digestalgo, &digest, NULL, 0);
2309 
2310 	if (digest != NULL && fidigest != NULL) {
2311 	    size_t diglen = rpmDigestLength(digestalgo);
2312 	    if (memcmp(digest, fidigest, diglen)) {
2313 		rc = RPMERR_DIGEST_MISMATCH;
2314 
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)
2320 			rc = 0;
2321 		}
2322 	    }
2323 	} else {
2324 	    rc = RPMERR_DIGEST_MISMATCH;
2325 	}
2326 	free(digest);
2327     }
2328 
2329 exit:
2330     return rc;
2331 }
2332 
rpmfiArchiveReadToFile(rpmfi fi,FD_t fd,int nodigest)2333 int rpmfiArchiveReadToFile(rpmfi fi, FD_t fd, int nodigest)
2334 {
2335     return rpmfiArchiveReadToFilePsm(fi, fd, nodigest, NULL);
2336 }
2337 
rpmfileStrerror(int rc)2338 char * rpmfileStrerror(int rc)
2339 {
2340     char *msg = NULL;
2341     const char *s = NULL;
2342     const char *prefix = "cpio";
2343     int myerrno = errno;
2344 
2345     switch (rc) {
2346     default:
2347 	break;
2348     case RPMERR_BAD_MAGIC:	s = _("Bad magic");		break;
2349     case RPMERR_BAD_HEADER:	s = _("Bad/unreadable  header");break;
2350 
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;
2371 
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");
2383 	break;
2384     }
2385 
2386     if (s != NULL) {
2387 	rasprintf(&msg, "%s: %s", prefix, s);
2388 	if ((rc <= RPMERR_CHECK_ERRNO) && myerrno) {
2389 	    rstrscat(&msg, _(" failed - "), strerror(myerrno), NULL);
2390 	}
2391     } else {
2392 	rasprintf(&msg, _("%s: (error 0x%x)"), prefix, rc);
2393     }
2394 
2395     return msg;
2396 }
2397