| 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 |