Bug Summary

File:lib/fprint.c
Warning:line 389, column 6
Value stored to 'foundfi' is never read

Annotated Source Code

1/**
2 * \file lib/fprint.c
3 */
4
5#include "system.h"
6
7#include <rpm/rpmfileutil.h> /* for rpmCleanPath */
8#include <rpm/rpmts.h>
9#include <rpm/rpmsq.h>
10
11#include "lib/rpmdb_internal.h"
12#include "lib/rpmfi_internal.h"
13#include "lib/rpmte_internal.h"
14#include "lib/fprint.h"
15#include "lib/misc.h"
16#include "debug.h"
17#include <libgen.h>
18
19/* Create new hash table type rpmFpEntryHash */
20#undef HASHTYPE
21#undef HTKEYTYPE
22#undef HTDATATYPE
23#define HASHTYPE rpmFpEntryHash
24#define HTKEYTYPE rpmsid
25#define HTDATATYPE const struct fprintCacheEntry_s *
26#include "lib/rpmhash.H"
27#include "lib/rpmhash.C"
28
29/* Create by-fingerprint hash table */
30#undef HASHTYPE
31#undef HTKEYTYPE
32#undef HTDATATYPE
33#define HASHTYPE rpmFpHash
34#define HTKEYTYPE const fingerPrint *
35#define HTDATATYPE struct rpmffi_s
36#include "lib/rpmhash.H"
37#include "lib/rpmhash.C"
38#undef HASHTYPE
39#undef HTKEYTYPE
40#undef HTDATATYPE
41
42static unsigned int sidHash(rpmsid sid)
43{
44 return sid;
45}
46
47static int sidCmp(rpmsid a, rpmsid b)
48{
49 return (a != b);
50}
51
52/**
53 * Finger print cache entry.
54 * This is really a directory and symlink cache. We don't differentiate between
55 * the two. We can prepopulate it, which allows us to easily conduct "fake"
56 * installs of a system w/o actually mounting filesystems.
57 */
58struct fprintCacheEntry_s {
59 rpmsid dirId; /*!< path to existing directory */
60 dev_t dev; /*!< stat(2) device number */
61 ino_t ino; /*!< stat(2) inode number */
62};
63
64/**
65 * Associates a trailing sub-directory and final base name with an existing
66 * directory finger print.
67 */
68struct fingerPrint_s {
69 /*! directory finger print entry (the directory path is stat(2)-able */
70 const struct fprintCacheEntry_s * entry;
71 /*! trailing sub-directory path (directories that are not stat(2)-able */
72 rpmsid subDirId;
73 rpmsid baseNameId; /*!< file base name id */
74};
75
76#define FP_ENTRY_EQUAL(a, b)(((a)->dev == (b)->dev) && ((a)->ino == (b)->
ino))
(((a)->dev == (b)->dev) && ((a)->ino == (b)->ino))
77
78#define FP_EQUAL(a, b)( ((((a).entry)->dev == ((b).entry)->dev) && ((
(a).entry)->ino == ((b).entry)->ino)) && ((a).baseNameId
== (b).baseNameId) && ((a).subDirId == (b).subDirId)
)
( \
79 FP_ENTRY_EQUAL((a).entry, (b).entry)((((a).entry)->dev == ((b).entry)->dev) && (((a
).entry)->ino == ((b).entry)->ino))
&& \
80 ((a).baseNameId == (b).baseNameId) && \
81 ((a).subDirId == (b).subDirId) \
82 )
83
84/**
85 * Finger print cache.
86 */
87struct fprintCache_s {
88 rpmFpEntryHash ht; /*!< hashed by dirName */
89 rpmFpHash fp; /*!< hashed by fingerprint */
90 rpmstrPool pool; /*!< string pool */
91};
92
93fingerPrintCache fpCacheCreate(int sizeHint, rpmstrPool pool)
94{
95 fingerPrintCache fpc;
96
97 fpc = xcalloc(1, sizeof(*fpc))rcalloc((1), (sizeof(*fpc)));
98 fpc->ht = rpmFpEntryHashCreate(sizeHint, sidHash, sidCmp,
99 NULL((void*)0), (rpmFpEntryHashFreeData)free);
100 fpc->pool = (pool != NULL((void*)0)) ? rpmstrPoolLink(pool) : rpmstrPoolCreate();
101 return fpc;
102}
103
104fingerPrintCache fpCacheFree(fingerPrintCache cache)
105{
106 if (cache) {
107 cache->ht = rpmFpEntryHashFree(cache->ht);
108 cache->fp = rpmFpHashFree(cache->fp);
109 cache->pool = rpmstrPoolFree(cache->pool);
110 free(cache);
111 }
112 return NULL((void*)0);
113}
114
115/**
116 * Find directory name entry in cache.
117 * @param cache pointer to fingerprint cache
118 * @param dirId string id to locate in cache
119 * @return pointer to directory name entry (or NULL if not found).
120 */
121static const struct fprintCacheEntry_s * cacheContainsDirectory(
122 fingerPrintCache cache, rpmsid dirId)
123{
124 const struct fprintCacheEntry_s ** data;
125
126 if (rpmFpEntryHashGetEntry(cache->ht, dirId, &data, NULL((void*)0), NULL((void*)0)))
127 return data[0];
128 return NULL((void*)0);
129}
130
131static char * canonDir(rpmstrPool pool, rpmsid dirNameId)
132{
133 const char * dirName = rpmstrPoolStr(pool, dirNameId);
134 size_t cdnl = rpmstrPoolStrlen(pool, dirNameId);;
135 char *cdnbuf = NULL((void*)0);
136
137 if (*dirName == '/') {
138 cdnbuf = xstrdup(dirName)rstrdup((dirName));
139 cdnbuf = rpmCleanPath(cdnbuf);
140 /* leave my trailing slashes along you b**** */
141 if (cdnl > 1)
142 cdnbuf = rstrcat(&cdnbuf, "/");
143 } else {
144 /* Using realpath on the arg isn't correct if the arg is a symlink,
145 * especially if the symlink is a dangling link. What we
146 * do instead is use realpath() on `.' and then append arg to
147 * the result.
148 */
149
150 /* if the current directory doesn't exist, we might fail.
151 oh well. likewise if it's too long. */
152
153 /* XXX we should let realpath() allocate if it can */
154 cdnbuf = xmalloc(PATH_MAX)rmalloc((4096));
155 cdnbuf[0] = '\0';
156 if (realpath(".", cdnbuf) != NULL((void*)0)) {
157 char *end = cdnbuf + strlen(cdnbuf);
158 if (end[-1] != '/') *end++ = '/';
159 end = stpncpy(end, dirName, PATH_MAX4096 - (end - cdnbuf));
160 *end = '\0';
161 (void)rpmCleanPath(cdnbuf); /* XXX possible /../ from concatenation */
162 end = cdnbuf + strlen(cdnbuf);
163 if (end[-1] != '/') *end++ = '/';
164 *end = '\0';
165 } else {
166 cdnbuf = _free(cdnbuf)rfree((cdnbuf));
167 }
168 }
169 return cdnbuf;
170}
171
172
173static int doLookupId(fingerPrintCache cache,
174 rpmsid dirNameId, rpmsid baseNameId,
175 fingerPrint *fp)
176{
177 struct stat sb;
178 const struct fprintCacheEntry_s * cacheHit;
179 char *cdn = canonDir(cache->pool, dirNameId);
180 rpmsid fpId;
181 size_t fpLen;
182
183 if (cdn == NULL((void*)0)) goto exit; /* XXX only if realpath() above fails */
184
185 memset(fp, 0, sizeof(*fp));
186 fpId = rpmstrPoolId(cache->pool, cdn, 1);
187 fpLen = rpmstrPoolStrlen(cache->pool, fpId);;
188
189 while (1) {
190 /* as we're stating paths here, we want to follow symlinks */
191 cacheHit = cacheContainsDirectory(cache, fpId);
192 if (cacheHit != NULL((void*)0)) {
193 fp->entry = cacheHit;
194 } else if (!stat(rpmstrPoolStr(cache->pool, fpId), &sb)) {
195 struct fprintCacheEntry_s * newEntry = xmalloc(sizeof(* newEntry))rmalloc((sizeof(* newEntry)));
196
197 newEntry->ino = sb.st_ino;
198 newEntry->dev = sb.st_dev;
199 newEntry->dirId = fpId;
200 fp->entry = newEntry;
201
202 rpmFpEntryHashAddEntry(cache->ht, fpId, fp->entry);
203 }
204
205 if (fp->entry) {
206 const char * subDir = cdn + fpLen - 1;
207 /* XXX don't bother saving '/' as subdir */
208 if (subDir[0] == '\0' || (subDir[0] == '/' && subDir[1] == '\0'))
209 subDir = NULL((void*)0);
210 fp->baseNameId = baseNameId;
211 if (subDir != NULL((void*)0))
212 fp->subDirId = rpmstrPoolId(cache->pool, subDir, 1);
213 goto exit;
214 }
215
216 /* stat of '/' just failed! */
217 if (fpLen == 1)
218 abort();
219
220 /* Find the parent directory and its id for the next round */
221 fpLen--;
222 while (fpLen > 1 && cdn[fpLen-1] != '/')
223 fpLen--;
224 fpId = rpmstrPoolIdn(cache->pool, cdn, fpLen, 1);
225 }
226
227exit:
228 free(cdn);
229 /* XXX TODO: failure from eg realpath() should be returned and handled */
230 return 0;
231}
232
233static int doLookup(fingerPrintCache cache,
234 const char * dirName, const char * baseName,
235 fingerPrint *fp)
236{
237 rpmsid dirNameId = rpmstrPoolId(cache->pool, dirName, 1);
238 rpmsid baseNameId = rpmstrPoolId(cache->pool, baseName, 1);
239 return doLookupId(cache, dirNameId, baseNameId, fp);
240}
241
242int fpLookup(fingerPrintCache cache,
243 const char * dirName, const char * baseName,
244 fingerPrint **fp)
245{
246 if (*fp == NULL((void*)0))
247 *fp = xcalloc(1, sizeof(**fp))rcalloc((1), (sizeof(**fp)));
248 return doLookup(cache, dirName, baseName, *fp);
249}
250
251/**
252 * Return hash value for a finger print.
253 * Hash based on dev and inode only!
254 * @param fp pointer to finger print entry
255 * @return hash value
256 */
257static unsigned int fpHashFunction(const fingerPrint * fp)
258{
259 unsigned int hash = 0;
260 int j;
261
262 hash = sidHash(fp->baseNameId);
263 if (fp->subDirId) hash ^= sidHash(fp->subDirId);
264
265 hash ^= ((unsigned)fp->entry->dev);
266 for (j=0; j<4; j++) hash ^= ((fp->entry->ino >> (8*j)) & 0xFF) << ((3-j)*8);
267
268 return hash;
269}
270
271int fpEqual(const fingerPrint * k1, const fingerPrint * k2)
272{
273 /* If the addresses are the same, so are the values. */
274 if (k1 == k2)
275 return 0;
276
277 /* Otherwise, compare fingerprints by value. */
278 if (FP_EQUAL(*k1, *k2)( ((((*k1).entry)->dev == ((*k2).entry)->dev) &&
(((*k1).entry)->ino == ((*k2).entry)->ino)) &&
((*k1).baseNameId == (*k2).baseNameId) && ((*k1).subDirId
== (*k2).subDirId) )
)
279 return 0;
280 return 1;
281
282}
283
284const char * fpEntryDir(fingerPrintCache cache, fingerPrint *fp)
285{
286 const char * dn = NULL((void*)0);
287 if (fp && fp->entry)
288 dn = rpmstrPoolStr(cache->pool, fp->entry->dirId);
289 return dn;
290}
291
292dev_t fpEntryDev(fingerPrintCache cache, fingerPrint *fp)
293{
294 return (fp && fp->entry) ? fp->entry->dev : 0;
295}
296
297int fpLookupEquals(fingerPrintCache cache, fingerPrint *fp,
298 const char * dirName, const char * baseName)
299{
300 struct fingerPrint_s ofp;
301 doLookup(cache, dirName, baseName, &ofp);
302 return FP_EQUAL(*fp, ofp)( ((((*fp).entry)->dev == ((ofp).entry)->dev) &&
(((*fp).entry)->ino == ((ofp).entry)->ino)) &&
((*fp).baseNameId == (ofp).baseNameId) && ((*fp).subDirId
== (ofp).subDirId) )
;
303}
304
305fingerPrint * fpLookupList(fingerPrintCache cache, rpmstrPool pool,
306 rpmsid * dirNames, rpmsid * baseNames,
307 const uint32_t * dirIndexes,
308 int fileCount)
309{
310 fingerPrint * fps = xmalloc(fileCount * sizeof(*fps))rmalloc((fileCount * sizeof(*fps)));
311 int i;
312
313 /*
314 * We could handle different pools easily enough, but there should be
315 * no need for that. Make sure we catch any oddball cases there might be
316 * lurking about.
317 */
318 assert(cache->pool == pool)({ if (cache->pool == pool) ; else __assert_fail ("cache->pool == pool"
, "fprint.c", 318, __PRETTY_FUNCTION__); })
;
319
320 for (i = 0; i < fileCount; i++) {
321 /* If this is in the same directory as the last file, don't bother
322 redoing all of this work */
323 if (i > 0 && dirIndexes[i - 1] == dirIndexes[i]) {
324 fps[i].entry = fps[i - 1].entry;
325 fps[i].subDirId = fps[i - 1].subDirId;
326 /* XXX if the pools are different, copy would be needed */
327 fps[i].baseNameId = baseNames[i];
328 } else {
329 doLookupId(cache, dirNames[dirIndexes[i]], baseNames[i], &fps[i]);
330 }
331 }
332 return fps;
333}
334
335/* Check file for to be installed symlinks in their path and correct their fp */
336static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, int filenr)
337{
338 rpmfiles fi = rpmteFiles(p);
339 struct fingerPrint_s current_fp;
340 const char *currentsubdir;
341 size_t lensubDir, bnStart, bnEnd;
342
343 struct rpmffi_s * recs;
344 int numRecs;
345 int i;
346 fingerPrint *fp = rpmfilesFps(fi) + filenr;
347 int symlinkcount = 0;
348 struct rpmffi_s ffi = { p, filenr};
349
350 if (fp->subDirId == 0) {
351 rpmFpHashAddEntry(fpc->fp, fp, ffi);
352 goto exit;
353 }
354
355 currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId);
356 lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId);
357 current_fp = *fp;
358
359 /* Set baseName to the upper most dir */
360 bnStart = bnEnd = 1;
361 while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
362 bnEnd++;
363 /* no subDir for now */
364 current_fp.subDirId = 0;
365
366 while (bnEnd < lensubDir) {
367 char found = 0;
368
369 current_fp.baseNameId = rpmstrPoolIdn(fpc->pool,
370 currentsubdir + bnStart,
371 bnEnd - bnStart, 1);
372
373 rpmFpHashGetEntry(symlinks, &current_fp, &recs, &numRecs, NULL((void*)0));
374
375 for (i = 0; i < numRecs; i++) {
376 rpmfiles foundfi = rpmteFiles(recs[i].p);
377 char const *linktarget = rpmfilesFLink(foundfi, recs[i].fileno);
378 char *link;
379
380 /* Ignore already removed (by eg %pretrans) links */
381 if (linktarget && rpmteType(recs[i].p) == TR_REMOVED) {
382 char *path = rpmfilesFN(foundfi, recs[i].fileno);
383 struct stat sb;
384 if (lstat(path, &sb) == -1)
385 linktarget = NULL((void*)0);
386 free(path);
387 }
388
389 foundfi = rpmfilesFree(foundfi);
Value stored to 'foundfi' is never read
390
391 if (linktarget && *linktarget != '\0') {
392 const char *bn;
393 /* this "directory" is a symlink */
394 link = NULL((void*)0);
395 if (*linktarget != '/') {
396 const char *dn, *subDir = NULL((void*)0);
397 dn = rpmstrPoolStr(fpc->pool, current_fp.entry->dirId);
398 if (current_fp.subDirId) {
399 subDir = rpmstrPoolStr(fpc->pool, current_fp.subDirId);
400 }
401 rstrscat(&link, dn, subDir ? subDir : "", "/", NULL((void*)0));
402 }
403 rstrscat(&link, linktarget, "/", NULL((void*)0));
404 if (strlen(currentsubdir + bnEnd)) {
405 rstrscat(&link, currentsubdir + bnEnd, NULL((void*)0));
406 }
407
408 bn = rpmstrPoolStr(fpc->pool, fp->baseNameId);
409 doLookup(fpc, link, bn, fp);
410
411 free(link);
412 symlinkcount++;
413
414 /* setup current_fp for the new path */
415 found = 1;
416 current_fp = *fp;
417 if (fp->subDirId == 0) {
418 /* directory exists - no need to look for symlinks */
419 rpmFpHashAddEntry(fpc->fp, fp, ffi);
420 goto exit;
421 }
422 currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId);
423 lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId);
424 /* no subDir for now */
425 current_fp.subDirId = 0;
426
427 /* Set baseName to the upper most dir */
428 bnStart = bnEnd = 1;
429 while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
430 bnEnd++;
431 break;
432
433 }
434 }
435 if (symlinkcount > 50) {
436 // found too many symlinks in the path
437 // most likley a symlink cicle
438 // giving up
439 // TODO warning/error
440 break;
441 }
442 if (found) {
443 continue; // restart loop after symlink
444 }
445
446 /* Set former baseName as subDir */
447 bnEnd++;
448 current_fp.subDirId = rpmstrPoolIdn(fpc->pool, currentsubdir, bnEnd, 1);
449
450 /* set baseName to the next lower dir */
451 bnStart = bnEnd;
452 while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/')
453 bnEnd++;
454 }
455 rpmFpHashAddEntry(fpc->fp, fp, ffi);
456
457exit:
458 rpmfilesFree(fi);
459}
460
461fingerPrint * fpCacheGetByFp(fingerPrintCache cache,
462 struct fingerPrint_s * fp, int ix,
463 struct rpmffi_s ** recs, int * numRecs)
464{
465 if (rpmFpHashGetEntry(cache->fp, fp + ix, recs, numRecs, NULL((void*)0)))
466 return fp + ix;
467 else
468 return NULL((void*)0);
469}
470
471void fpCachePopulate(fingerPrintCache fpc, rpmts ts, int fileCount)
472{
473 rpmtsi pi;
474 rpmte p;
475 rpmfs fs;
476 rpmfiles fi;
477 int i, fc;
478
479 if (fpc->fp == NULL((void*)0))
480 fpc->fp = rpmFpHashCreate(fileCount/2 + 10001, fpHashFunction, fpEqual,
481 NULL((void*)0), NULL((void*)0));
482
483 rpmFpHash symlinks = rpmFpHashCreate(fileCount/16+16, fpHashFunction, fpEqual, NULL((void*)0), NULL((void*)0));
484
485 pi = rpmtsiInit(ts);
486 while ((p = rpmtsiNext(pi, 0)) != NULL((void*)0)) {
487 fingerPrint *fpList;
488 (void) rpmsqPoll();
489
490 if ((fi = rpmteFiles(p)) == NULL((void*)0))
491 continue; /* XXX can't happen */
492
493 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
494 rpmfilesFpLookup(fi, fpc);
495 fs = rpmteGetFileStates(p);
496 fc = rpmfsFC(fs);
497 fpList = rpmfilesFps(fi);
498 /* collect symbolic links */
499 for (i = 0; i < fc; i++) {
500 struct rpmffi_s ffi;
501 char const *linktarget;
502 if (XFA_SKIPPING(rpmfsGetAction(fs, i))((rpmfsGetAction(fs, i)) == FA_SKIP || (rpmfsGetAction(fs, i)
) == FA_SKIPNSTATE || (rpmfsGetAction(fs, i)) == FA_SKIPNETSHARED
|| (rpmfsGetAction(fs, i)) == FA_SKIPCOLOR)
)
503 continue;
504 linktarget = rpmfilesFLink(fi, i);
505 if (!(linktarget && *linktarget != '\0'))
506 continue;
507 ffi.p = p;
508 ffi.fileno = i;
509 rpmFpHashAddEntry(symlinks, fpList + i, ffi);
510 }
511 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
512 rpmfilesFree(fi);
513 }
514 rpmtsiFree(pi);
515
516 /* ===============================================
517 * Check fingerprints if they contain symlinks
518 * and add them to the hash table
519 */
520
521 pi = rpmtsiInit(ts);
522 while ((p = rpmtsiNext(pi, 0)) != NULL((void*)0)) {
523 (void) rpmsqPoll();
524
525 fs = rpmteGetFileStates(p);
526 fc = rpmfsFC(fs);
527 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
528 for (i = 0; i < fc; i++) {
529 if (XFA_SKIPPING(rpmfsGetAction(fs, i))((rpmfsGetAction(fs, i)) == FA_SKIP || (rpmfsGetAction(fs, i)
) == FA_SKIPNSTATE || (rpmfsGetAction(fs, i)) == FA_SKIPNETSHARED
|| (rpmfsGetAction(fs, i)) == FA_SKIPCOLOR)
)
530 continue;
531 fpLookupSubdir(symlinks, fpc, p, i);
532 }
533 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
534 }
535 rpmtsiFree(pi);
536
537 rpmFpHashFree(symlinks);
538}
539