Bug Summary

File:lib/rpmfi.c
Warning:line 1487, column 5
Value stored to 'files' is never read

Annotated Source Code

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