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