Bug Summary

File:lib/headerutil.c
Warning:line 267, column 2
Value stored to 'needle' is never read

Annotated Source Code

1/** \ingroup rpmdb
2 * \file lib/headerutil.c
3 */
4
5#include "system.h"
6
7#include <rpm/rpmtypes.h>
8#include <rpm/header.h>
9#include <rpm/rpmstring.h>
10#include <rpm/rpmds.h>
11
12#include "debug.h"
13
14int headerIsSource(Header h)
15{
16 return (!headerIsEntry(h, RPMTAG_SOURCERPM));
17}
18
19Header headerCopy(Header h)
20{
21 Header nh = headerNew();
22 HeaderIterator hi;
23 struct rpmtd_s td;
24
25 hi = headerInitIterator(h);
26 while (headerNext(hi, &td)) {
27 if (rpmtdCount(&td) > 0) {
28 (void) headerPut(nh, &td, HEADERPUT_DEFAULT);
29 }
30 rpmtdFreeData(&td);
31 }
32 headerFreeIterator(hi);
33
34 return nh;
35}
36
37void headerCopyTags(Header headerFrom, Header headerTo,
38 const rpmTagVal * tagstocopy)
39{
40 const rpmTagVal * p;
41 struct rpmtd_s td;
42
43 if (headerFrom == headerTo)
44 return;
45
46 for (p = tagstocopy; *p != 0; p++) {
47 if (headerIsEntry(headerTo, *p))
48 continue;
49 if (!headerGet(headerFrom, *p, &td, (HEADERGET_MINMEM|HEADERGET_RAW)))
50 continue;
51 (void) headerPut(headerTo, &td, HEADERPUT_DEFAULT);
52 rpmtdFreeData(&td);
53 }
54}
55
56char * headerGetAsString(Header h, rpmTagVal tag)
57{
58 char *res = NULL((void*)0);
59 struct rpmtd_s td;
60
61 if (headerGet(h, tag, &td, HEADERGET_EXT)) {
62 if (rpmtdCount(&td) == 1) {
63 res = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL((void*)0));
64 }
65 rpmtdFreeData(&td);
66 }
67 return res;
68}
69
70const char * headerGetString(Header h, rpmTagVal tag)
71{
72 const char *res = NULL((void*)0);
73 struct rpmtd_s td;
74
75 if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
76 if (rpmtdCount(&td) == 1) {
77 res = rpmtdGetString(&td);
78 }
79 rpmtdFreeData(&td);
80 }
81 return res;
82}
83
84uint64_t headerGetNumber(Header h, rpmTagVal tag)
85{
86 uint64_t res = 0;
87 struct rpmtd_s td;
88
89 if (headerGet(h, tag, &td, HEADERGET_EXT)) {
90 if (rpmtdCount(&td) == 1) {
91 res = rpmtdGetNumber(&td);
92 }
93 rpmtdFreeData(&td);
94 }
95 return res;
96}
97
98/*
99 * Sanity check data types against tag table before putting. Assume
100 * append on all array-types.
101 */
102static int headerPutType(Header h, rpmTagVal tag, rpmTagType reqtype,
103 rpm_constdata_t data, rpm_count_t size)
104{
105 struct rpmtd_s td;
106 rpmTagType type = rpmTagGetTagType(tag);
107 rpmTagReturnType retype = rpmTagGetReturnType(tag);
108 headerPutFlags flags = HEADERPUT_APPEND;
109 int valid = 1;
110
111 /* Basic sanity checks: type must match and there must be data to put */
112 if (type != reqtype
113 || size < 1 || data == NULL((void*)0) || h == NULL((void*)0)) {
114 valid = 0;
115 }
116
117 /*
118 * Non-array types can't be appended to. Binary types use size
119 * for data length, for other non-array types size must be 1.
120 */
121 if (retype != RPM_ARRAY_RETURN_TYPE) {
122 flags = HEADERPUT_DEFAULT;
123 if (type != RPM_BIN_TYPE && size != 1) {
124 valid = 0;
125 }
126 }
127
128 if (valid) {
129 rpmtdReset(&td);
130 td.tag = tag;
131 td.type = type;
132 td.data = (void *) data;
133 td.count = size;
134
135 valid = headerPut(h, &td, flags);
136 }
137
138 return valid;
139}
140
141int headerPutString(Header h, rpmTagVal tag, const char *val)
142{
143 rpmTagType type = rpmTagGetTagType(tag);
144 const void *sptr = NULL((void*)0);
145
146 /* string arrays expect char **, arrange that */
147 if (type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE) {
148 sptr = &val;
149 } else if (type == RPM_STRING_TYPE) {
150 sptr = val;
151 } else {
152 return 0;
153 }
154
155 return headerPutType(h, tag, type, sptr, 1);
156}
157
158int headerPutStringArray(Header h, rpmTagVal tag, const char **array, rpm_count_t size)
159{
160 return headerPutType(h, tag, RPM_STRING_ARRAY_TYPE, array, size);
161}
162
163int headerPutChar(Header h, rpmTagVal tag, const char *val, rpm_count_t size)
164{
165 return headerPutType(h, tag, RPM_CHAR_TYPE, val, size);
166}
167
168int headerPutUint8(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size)
169{
170 return headerPutType(h, tag, RPM_INT8_TYPE, val, size);
171}
172
173int headerPutUint16(Header h, rpmTagVal tag, const uint16_t *val, rpm_count_t size)
174{
175 return headerPutType(h, tag, RPM_INT16_TYPE, val, size);
176}
177
178int headerPutUint32(Header h, rpmTagVal tag, const uint32_t *val, rpm_count_t size)
179{
180 return headerPutType(h, tag, RPM_INT32_TYPE, val, size);
181}
182
183int headerPutUint64(Header h, rpmTagVal tag, const uint64_t *val, rpm_count_t size)
184{
185 return headerPutType(h, tag, RPM_INT64_TYPE, val, size);
186}
187
188int headerPutBin(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size)
189{
190 return headerPutType(h, tag, RPM_BIN_TYPE, val, size);
191}
192
193static int dncmp(const void * a, const void * b)
194{
195 const char *const * first = a;
196 const char *const * second = b;
197 return strcmp(*first, *second);
198}
199
200static void compressFilelist(Header h)
201{
202 struct rpmtd_s fileNames;
203 char ** dirNames;
204 const char ** baseNames;
205 uint32_t * dirIndexes;
206 rpm_count_t count, realCount = 0;
207 int i;
208 int dirIndex = -1;
209
210 /*
211 * This assumes the file list is already sorted, and begins with a
212 * single '/'. That assumption isn't critical, but it makes things go
213 * a bit faster.
214 */
215
216 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
217 headerDel(h, RPMTAG_OLDFILENAMES);
218 return; /* Already converted. */
219 }
220
221 if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
222 return;
223 count = rpmtdCount(&fileNames);
224 if (count < 1)
225 return;
226
227 dirNames = xmalloc(sizeof(*dirNames) * count)rmalloc((sizeof(*dirNames) * count)); /* worst case */
228 baseNames = xmalloc(sizeof(*dirNames) * count)rmalloc((sizeof(*dirNames) * count));
229 dirIndexes = xmalloc(sizeof(*dirIndexes) * count)rmalloc((sizeof(*dirIndexes) * count));
230
231 /* HACK. Source RPM, so just do things differently */
232 { const char *fn = rpmtdGetString(&fileNames);
233 if (fn && *fn != '/') {
234 dirIndex = 0;
235 dirNames[dirIndex] = xstrdup("")rstrdup((""));
236 while ((i = rpmtdNext(&fileNames)) >= 0) {
237 dirIndexes[i] = dirIndex;
238 baseNames[i] = rpmtdGetString(&fileNames);
239 realCount++;
240 }
241 goto exit;
242 }
243 }
244
245 /*
246 * XXX EVIL HACK, FIXME:
247 * This modifies (and then restores) a const string from rpmtd
248 * through basename retrieved from strrchr() which silently
249 * casts away const on return.
250 */
251 while ((i = rpmtdNext(&fileNames)) >= 0) {
252 char ** needle;
253 char savechar;
254 char * baseName;
255 size_t len;
256 char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */
257
258 if (filename == NULL((void*)0)) /* XXX can't happen */
259 continue;
260 baseName = strrchr(filename, '/');
261 if (baseName == NULL((void*)0)) {
262 baseName = filename;
263 } else {
264 baseName += 1;
265 }
266 len = baseName - filename;
267 needle = dirNames;
Value stored to 'needle' is never read
268 savechar = *baseName;
269 *baseName = '\0';
270 if (dirIndex < 0 ||
271 (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL((void*)0)) {
272 char *s = xmalloc(len + 1)rmalloc((len + 1));
273 rstrlcpy(s, filename, len + 1);
274 dirIndexes[realCount] = ++dirIndex;
275 dirNames[dirIndex] = s;
276 } else
277 dirIndexes[realCount] = needle - dirNames;
278
279 *baseName = savechar;
280 baseNames[realCount] = baseName;
281 realCount++;
282 }
283
284exit:
285 if (count > 0) {
286 headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, realCount);
287 headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, realCount);
288 headerPutStringArray(h, RPMTAG_DIRNAMES,
289 (const char **) dirNames, dirIndex + 1);
290 }
291
292 rpmtdFreeData(&fileNames);
293 for (i = 0; i <= dirIndex; i++) {
294 free(dirNames[i]);
295 }
296 free(dirNames);
297 free(baseNames);
298 free(dirIndexes);
299
300 headerDel(h, RPMTAG_OLDFILENAMES);
301}
302
303static void expandFilelist(Header h)
304{
305 struct rpmtd_s filenames;
306
307 if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
308 (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
309 if (rpmtdCount(&filenames) < 1)
310 return;
311 rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
312 headerPut(h, &filenames, HEADERPUT_DEFAULT);
313 rpmtdFreeData(&filenames);
314 }
315
316 (void) headerDel(h, RPMTAG_DIRNAMES);
317 (void) headerDel(h, RPMTAG_BASENAMES);
318 (void) headerDel(h, RPMTAG_DIRINDEXES);
319}
320
321/*
322 * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
323 * Retrofit an explicit "Provides: name = epoch:version-release.
324 */
325static void providePackageNVR(Header h)
326{
327 const char *name = headerGetString(h, RPMTAG_NAME);
328 char *pEVR = headerGetAsString(h, RPMTAG_EVR);
329 rpmsenseFlags pFlags = RPMSENSE_EQUAL;
330 int bingo = 1;
331 struct rpmtd_s pnames;
332 rpmds hds, nvrds;
333
334 /* Generate provides for this package name-version-release. */
335 if (!(name && pEVR))
336 return;
337
338 /*
339 * Rpm prior to 3.0.3 does not have versioned provides.
340 * If no provides at all are available, we can just add.
341 */
342 if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
343 goto exit;
344 }
345
346 /*
347 * Otherwise, fill in entries on legacy packages.
348 */
349 if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
350 while (rpmtdNext(&pnames) >= 0) {
351 rpmsenseFlags fdummy = RPMSENSE_ANY;
352
353 headerPutString(h, RPMTAG_PROVIDEVERSION, "");
354 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
355 }
356 goto exit;
357 }
358
359 /* see if we already have this provide */
360 hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
361 nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
362 if (rpmdsFind(hds, nvrds) >= 0) {
363 bingo = 0;
364 }
365 rpmdsFree(hds);
366 rpmdsFree(nvrds);
367
368
369exit:
370 if (bingo) {
371 headerPutString(h, RPMTAG_PROVIDENAME, name);
372 headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
373 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
374 }
375 rpmtdFreeData(&pnames);
376 free(pEVR);
377}
378
379static void legacyRetrofit(Header h)
380{
381 /*
382 * The file list was moved to a more compressed format which not
383 * only saves memory (nice), but gives fingerprinting a nice, fat
384 * speed boost (very nice). Go ahead and convert old headers to
385 * the new style (this is a noop for new headers).
386 */
387 compressFilelist(h);
388
389 /* Retrofit "Provide: name = EVR" for binary packages. */
390 if (!headerIsSource(h)) {
391 providePackageNVR(h);
392 }
393}
394
395int headerConvert(Header h, int op)
396{
397 int rc = 1;
398
399 if (h == NULL((void*)0))
400 return 0;
401
402 switch (op) {
403 case HEADERCONV_EXPANDFILELIST:
404 expandFilelist(h);
405 break;
406 case HEADERCONV_COMPRESSFILELIST:
407 compressFilelist(h);
408 break;
409 case HEADERCONV_RETROFIT_V3:
410 legacyRetrofit(h);
411 break;
412 default:
413 rc = 0;
414 break;
415 }
416 return rc;
417};
418