File: | lib/headerutil.c |
Warning: | line 267, column 2 Value stored to 'needle' is never read |
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 | |
14 | int headerIsSource(Header h) |
15 | { |
16 | return (!headerIsEntry(h, RPMTAG_SOURCERPM)); |
17 | } |
18 | |
19 | Header 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 | |
37 | void 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 | |
56 | char * 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 | |
70 | const 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 | |
84 | uint64_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 | */ |
102 | static 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 | |
141 | int 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 | |
158 | int 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 | |
163 | int 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 | |
168 | int 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 | |
173 | int 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 | |
178 | int 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 | |
183 | int 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 | |
188 | int 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 | |
193 | static 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 | |
200 | static 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 | |
284 | exit: |
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 | |
303 | static 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 | */ |
325 | static 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 | |
369 | exit: |
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 | |
379 | static 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 | |
395 | int 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 |