| File: | src/repo_write.c |
| Warning: | line 1604, column 3 Value stored to 'keyused' is never read |
| 1 | /* |
| 2 | * Copyright (c) 2007-2011, Novell Inc. |
| 3 | * |
| 4 | * This program is licensed under the BSD license, read LICENSE.BSD |
| 5 | * for further information |
| 6 | */ |
| 7 | |
| 8 | /* |
| 9 | * repo_write.c |
| 10 | * |
| 11 | * Write Repo data out to a file in solv format |
| 12 | * |
| 13 | * See doc/README.format for a description |
| 14 | * of the binary file format |
| 15 | * |
| 16 | */ |
| 17 | |
| 18 | #include <sys/types.h> |
| 19 | #include <limits.h> |
| 20 | #include <fcntl.h> |
| 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> |
| 23 | #include <string.h> |
| 24 | #include <assert.h> |
| 25 | #include <errno(*__errno_location ()).h> |
| 26 | |
| 27 | #include "pool.h" |
| 28 | #include "util.h" |
| 29 | #include "repo_write.h" |
| 30 | #include "repopage.h" |
| 31 | |
| 32 | /*------------------------------------------------------------------*/ |
| 33 | /* Id map optimizations */ |
| 34 | |
| 35 | typedef struct needid { |
| 36 | Id need; |
| 37 | Id map; |
| 38 | } NeedId; |
| 39 | |
| 40 | |
| 41 | #define RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) (needid[0].map + GETRELID(id)((id) ^ 0x80000000)) |
| 42 | |
| 43 | /* |
| 44 | * increment need Id |
| 45 | * idarray: array of Ids, ID_NULL terminated |
| 46 | * needid: array of Id->NeedId |
| 47 | * |
| 48 | * return size of array (including trailing zero) |
| 49 | * |
| 50 | */ |
| 51 | |
| 52 | static void |
| 53 | incneedid(Pool *pool, Id id, NeedId *needid) |
| 54 | { |
| 55 | while (ISRELDEP(id)(((id) & 0x80000000) != 0)) |
| 56 | { |
| 57 | Reldep *rd = GETRELDEP(pool, id)((pool)->rels + ((id) ^ 0x80000000)); |
| 58 | needid[RELOFF(id)(needid[0].map + ((id) ^ 0x80000000))].need++; |
| 59 | if (ISRELDEP(rd->evr)(((rd->evr) & 0x80000000) != 0)) |
| 60 | incneedid(pool, rd->evr, needid); |
| 61 | else |
| 62 | needid[rd->evr].need++; |
| 63 | id = rd->name; |
| 64 | } |
| 65 | needid[id].need++; |
| 66 | } |
| 67 | |
| 68 | static int |
| 69 | incneedidarray(Pool *pool, Id *idarray, NeedId *needid) |
| 70 | { |
| 71 | Id id; |
| 72 | int n = 0; |
| 73 | |
| 74 | if (!idarray) |
| 75 | return 0; |
| 76 | while ((id = *idarray++) != 0) |
| 77 | { |
| 78 | n++; |
| 79 | while (ISRELDEP(id)(((id) & 0x80000000) != 0)) |
| 80 | { |
| 81 | Reldep *rd = GETRELDEP(pool, id)((pool)->rels + ((id) ^ 0x80000000)); |
| 82 | needid[RELOFF(id)(needid[0].map + ((id) ^ 0x80000000))].need++; |
| 83 | if (ISRELDEP(rd->evr)(((rd->evr) & 0x80000000) != 0)) |
| 84 | incneedid(pool, rd->evr, needid); |
| 85 | else |
| 86 | needid[rd->evr].need++; |
| 87 | id = rd->name; |
| 88 | } |
| 89 | needid[id].need++; |
| 90 | } |
| 91 | return n + 1; |
| 92 | } |
| 93 | |
| 94 | |
| 95 | /* |
| 96 | * |
| 97 | */ |
| 98 | |
| 99 | static int |
| 100 | needid_cmp_need(const void *ap, const void *bp, void *dp) |
| 101 | { |
| 102 | const NeedId *a = ap; |
| 103 | const NeedId *b = bp; |
| 104 | int r; |
| 105 | r = b->need - a->need; |
| 106 | if (r) |
| 107 | return r; |
| 108 | return a->map - b->map; |
| 109 | } |
| 110 | |
| 111 | static int |
| 112 | needid_cmp_need_s(const void *ap, const void *bp, void *dp) |
| 113 | { |
| 114 | const NeedId *a = ap; |
| 115 | const NeedId *b = bp; |
| 116 | Stringpool *spool = dp; |
| 117 | const char *as; |
| 118 | const char *bs; |
| 119 | |
| 120 | int r; |
| 121 | r = b->need - a->need; |
| 122 | if (r) |
| 123 | return r; |
| 124 | as = spool->stringspace + spool->strings[a->map]; |
| 125 | bs = spool->stringspace + spool->strings[b->map]; |
| 126 | return strcmp(as, bs); |
| 127 | } |
| 128 | |
| 129 | |
| 130 | /*------------------------------------------------------------------*/ |
| 131 | /* output helper routines, used for writing the header */ |
| 132 | /* (the data itself is accumulated in memory and written with |
| 133 | * write_blob) */ |
| 134 | |
| 135 | /* |
| 136 | * unsigned 32-bit |
| 137 | */ |
| 138 | |
| 139 | static void |
| 140 | write_u32(Repodata *data, unsigned int x) |
| 141 | { |
| 142 | FILE *fp = data->fp; |
| 143 | if (data->error) |
| 144 | return; |
| 145 | if (putc(x >> 24, fp)_IO_putc (x >> 24, fp) == EOF(-1) || |
| 146 | putc(x >> 16, fp)_IO_putc (x >> 16, fp) == EOF(-1) || |
| 147 | putc(x >> 8, fp)_IO_putc (x >> 8, fp) == EOF(-1) || |
| 148 | putc(x, fp)_IO_putc (x, fp) == EOF(-1)) |
| 149 | { |
| 150 | data->error = pool_error(data->repo->pool, -1, "write error u32: %s", strerror(errno(*__errno_location ()))); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | |
| 155 | /* |
| 156 | * unsigned 8-bit |
| 157 | */ |
| 158 | |
| 159 | static void |
| 160 | write_u8(Repodata *data, unsigned int x) |
| 161 | { |
| 162 | if (data->error) |
| 163 | return; |
| 164 | if (putc(x, data->fp)_IO_putc (x, data->fp) == EOF(-1)) |
| 165 | { |
| 166 | data->error = pool_error(data->repo->pool, -1, "write error u8: %s", strerror(errno(*__errno_location ()))); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /* |
| 171 | * data blob |
| 172 | */ |
| 173 | |
| 174 | static void |
| 175 | write_blob(Repodata *data, void *blob, int len) |
| 176 | { |
| 177 | if (data->error) |
| 178 | return; |
| 179 | if (len && fwrite(blob, len, 1, data->fp) != 1) |
| 180 | { |
| 181 | data->error = pool_error(data->repo->pool, -1, "write error blob: %s", strerror(errno(*__errno_location ()))); |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | /* |
| 186 | * Id |
| 187 | */ |
| 188 | |
| 189 | static void |
| 190 | write_id(Repodata *data, Id x) |
| 191 | { |
| 192 | FILE *fp = data->fp; |
| 193 | if (data->error) |
| 194 | return; |
| 195 | if (x >= (1 << 14)) |
| 196 | { |
| 197 | if (x >= (1 << 28)) |
| 198 | putc((x >> 28) | 128, fp)_IO_putc ((x >> 28) | 128, fp); |
| 199 | if (x >= (1 << 21)) |
| 200 | putc((x >> 21) | 128, fp)_IO_putc ((x >> 21) | 128, fp); |
| 201 | putc((x >> 14) | 128, fp)_IO_putc ((x >> 14) | 128, fp); |
| 202 | } |
| 203 | if (x >= (1 << 7)) |
| 204 | putc((x >> 7) | 128, fp)_IO_putc ((x >> 7) | 128, fp); |
| 205 | if (putc(x & 127, fp)_IO_putc (x & 127, fp) == EOF(-1)) |
| 206 | { |
| 207 | data->error = pool_error(data->repo->pool, -1, "write error id: %s", strerror(errno(*__errno_location ()))); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | static inline void |
| 212 | write_id_eof(Repodata *data, Id x, int eof) |
| 213 | { |
| 214 | if (x >= 64) |
| 215 | x = (x & 63) | ((x & ~63) << 1); |
| 216 | write_id(data, x | (eof ? 0 : 64)); |
| 217 | } |
| 218 | |
| 219 | |
| 220 | |
| 221 | static inline void |
| 222 | write_str(Repodata *data, const char *str) |
| 223 | { |
| 224 | if (data->error) |
| 225 | return; |
| 226 | if (fputs(str, data->fp) == EOF(-1) || putc(0, data->fp)_IO_putc (0, data->fp) == EOF(-1)) |
| 227 | { |
| 228 | data->error = pool_error(data->repo->pool, -1, "write error str: %s", strerror(errno(*__errno_location ()))); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | * Array of Ids |
| 234 | */ |
| 235 | |
| 236 | static void |
| 237 | write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids) |
| 238 | { |
| 239 | Id id; |
| 240 | if (!ids) |
| 241 | return; |
| 242 | if (!*ids) |
| 243 | { |
| 244 | write_u8(data, 0); |
| 245 | return; |
| 246 | } |
| 247 | for (;;) |
| 248 | { |
| 249 | id = *ids++; |
| 250 | if (needid) |
| 251 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 252 | if (id >= 64) |
| 253 | id = (id & 63) | ((id & ~63) << 1); |
| 254 | if (!*ids) |
| 255 | { |
| 256 | write_id(data, id); |
| 257 | return; |
| 258 | } |
| 259 | write_id(data, id | 64); |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | static int |
| 264 | cmp_ids(const void *pa, const void *pb, void *dp) |
| 265 | { |
| 266 | Id a = *(Id *)pa; |
| 267 | Id b = *(Id *)pb; |
| 268 | return a - b; |
| 269 | } |
| 270 | |
| 271 | #if 0 |
| 272 | static void |
| 273 | write_idarray_sort(Repodata *data, Pool *pool, NeedId *needid, Id *ids, Id marker) |
| 274 | { |
| 275 | int len, i; |
| 276 | Id lids[64], *sids; |
| 277 | |
| 278 | if (!ids) |
| 279 | return; |
| 280 | if (!*ids) |
| 281 | { |
| 282 | write_u8(data, 0); |
| 283 | return; |
| 284 | } |
| 285 | for (len = 0; len < 64 && ids[len]; len++) |
| 286 | { |
| 287 | Id id = ids[len]; |
| 288 | if (needid) |
| 289 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 290 | lids[len] = id; |
| 291 | } |
| 292 | if (ids[len]) |
| 293 | { |
| 294 | for (i = len + 1; ids[i]; i++) |
| 295 | ; |
| 296 | sids = solv_malloc2(i, sizeof(Id)); |
| 297 | memcpy(sids, lids, 64 * sizeof(Id)); |
| 298 | for (; ids[len]; len++) |
| 299 | { |
| 300 | Id id = ids[len]; |
| 301 | if (needid) |
| 302 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 303 | sids[len] = id; |
| 304 | } |
| 305 | } |
| 306 | else |
| 307 | sids = lids; |
| 308 | |
| 309 | /* That bloody solvable:prereqmarker needs to stay in position :-( */ |
| 310 | if (needid) |
| 311 | marker = needid[marker].need; |
| 312 | for (i = 0; i < len; i++) |
| 313 | if (sids[i] == marker) |
| 314 | break; |
| 315 | if (i > 1) |
| 316 | solv_sort(sids, i, sizeof(Id), cmp_ids, 0); |
| 317 | if ((len - i) > 2) |
| 318 | solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0); |
| 319 | |
| 320 | Id id, old = 0; |
| 321 | |
| 322 | /* The differencing above produces many runs of ones and twos. I tried |
| 323 | fairly elaborate schemes to RLE those, but they give only very mediocre |
| 324 | improvements in compression, as coding the escapes costs quite some |
| 325 | space. Even if they are coded only as bits in IDs. The best improvement |
| 326 | was about 2.7% for the whole .solv file. It's probably better to |
| 327 | invest some complexity into sharing idarrays, than RLEing. */ |
| 328 | for (i = 0; i < len - 1; i++) |
| 329 | { |
| 330 | id = sids[i]; |
| 331 | /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker, |
| 332 | hence all real differences are offsetted by 1. Otherwise we would |
| 333 | have to handle negative differences, which would cost code space for |
| 334 | the encoding of the sign. We loose the exact mapping of prereq here, |
| 335 | but we know the result, so we can recover from that in the reader. */ |
| 336 | if (id == marker) |
| 337 | id = old = 0; |
| 338 | else |
| 339 | { |
| 340 | id = id - old + 1; |
| 341 | old = sids[i]; |
| 342 | } |
| 343 | /* XXX If difference is zero we have multiple equal elements, |
| 344 | we might want to skip writing them out. */ |
| 345 | if (id >= 64) |
| 346 | id = (id & 63) | ((id & ~63) << 1); |
| 347 | write_id(data, id | 64); |
| 348 | } |
| 349 | id = sids[i]; |
| 350 | if (id == marker) |
| 351 | id = 0; |
| 352 | else |
| 353 | id = id - old + 1; |
| 354 | if (id >= 64) |
| 355 | id = (id & 63) | ((id & ~63) << 1); |
| 356 | write_id(data, id); |
| 357 | if (sids != lids) |
| 358 | solv_free(sids); |
| 359 | } |
| 360 | #endif |
| 361 | |
| 362 | |
| 363 | struct extdata { |
| 364 | unsigned char *buf; |
| 365 | int len; |
| 366 | }; |
| 367 | |
| 368 | struct cbdata { |
| 369 | Repo *repo; |
| 370 | Repodata *target; |
| 371 | |
| 372 | Stringpool *ownspool; |
| 373 | Dirpool *owndirpool; |
| 374 | |
| 375 | Id *keymap; |
| 376 | int nkeymap; |
| 377 | Id *keymapstart; |
| 378 | |
| 379 | NeedId *needid; |
| 380 | |
| 381 | Id *schema; /* schema construction space */ |
| 382 | Id *sp; /* pointer in above */ |
| 383 | Id *oldschema, *oldsp; |
| 384 | |
| 385 | Id *solvschemata; |
| 386 | Id *subschemata; |
| 387 | int nsubschemata; |
| 388 | int current_sub; |
| 389 | |
| 390 | struct extdata *extdata; |
| 391 | |
| 392 | Id *dirused; |
| 393 | |
| 394 | Id vstart; |
| 395 | |
| 396 | Id maxdata; |
| 397 | Id lastlen; |
| 398 | |
| 399 | int doingsolvables; /* working on solvables data */ |
| 400 | int filelistmode; |
| 401 | }; |
| 402 | |
| 403 | #define NEEDED_BLOCK1023 1023 |
| 404 | #define SCHEMATA_BLOCK31 31 |
| 405 | #define SCHEMATADATA_BLOCK255 255 |
| 406 | #define EXTDATA_BLOCK4095 4095 |
| 407 | |
| 408 | static inline void |
| 409 | data_addid(struct extdata *xd, Id sx) |
| 410 | { |
| 411 | unsigned int x = (unsigned int)sx; |
| 412 | unsigned char *dp; |
| 413 | |
| 414 | xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK4095); |
| 415 | dp = xd->buf + xd->len; |
| 416 | |
| 417 | if (x >= (1 << 14)) |
| 418 | { |
| 419 | if (x >= (1 << 28)) |
| 420 | *dp++ = (x >> 28) | 128; |
| 421 | if (x >= (1 << 21)) |
| 422 | *dp++ = (x >> 21) | 128; |
| 423 | *dp++ = (x >> 14) | 128; |
| 424 | } |
| 425 | if (x >= (1 << 7)) |
| 426 | *dp++ = (x >> 7) | 128; |
| 427 | *dp++ = x & 127; |
| 428 | xd->len = dp - xd->buf; |
| 429 | } |
| 430 | |
| 431 | static inline void |
| 432 | data_addideof(struct extdata *xd, Id sx, int eof) |
| 433 | { |
| 434 | unsigned int x = (unsigned int)sx; |
| 435 | unsigned char *dp; |
| 436 | |
| 437 | xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK4095); |
| 438 | dp = xd->buf + xd->len; |
| 439 | |
| 440 | if (x >= (1 << 13)) |
| 441 | { |
| 442 | if (x >= (1 << 27)) |
| 443 | *dp++ = (x >> 27) | 128; |
| 444 | if (x >= (1 << 20)) |
| 445 | *dp++ = (x >> 20) | 128; |
| 446 | *dp++ = (x >> 13) | 128; |
| 447 | } |
| 448 | if (x >= (1 << 6)) |
| 449 | *dp++ = (x >> 6) | 128; |
| 450 | *dp++ = eof ? (x & 63) : (x & 63) | 64; |
| 451 | xd->len = dp - xd->buf; |
| 452 | } |
| 453 | |
| 454 | static inline int |
| 455 | data_addideof_len(Id sx) |
| 456 | { |
| 457 | unsigned int x = (unsigned int)sx; |
| 458 | if (x >= (1 << 13)) |
| 459 | { |
| 460 | if (x >= (1 << 27)) |
| 461 | return 5; |
| 462 | return x >= (1 << 20) ? 4 : 3; |
| 463 | } |
| 464 | return x >= (1 << 6) ? 2 : 1; |
| 465 | } |
| 466 | |
| 467 | static void |
| 468 | data_addid64(struct extdata *xd, unsigned int x, unsigned int hx) |
| 469 | { |
| 470 | if (hx) |
| 471 | { |
| 472 | if (hx > 7) |
| 473 | { |
| 474 | data_addid(xd, (Id)(hx >> 3)); |
| 475 | xd->buf[xd->len - 1] |= 128; |
| 476 | hx &= 7; |
| 477 | } |
| 478 | data_addid(xd, (Id)(x | 0x80000000)); |
| 479 | xd->buf[xd->len - 5] = (x >> 28) | (hx << 4) | 128; |
| 480 | } |
| 481 | else |
| 482 | data_addid(xd, (Id)x); |
| 483 | } |
| 484 | |
| 485 | static void |
| 486 | data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker) |
| 487 | { |
| 488 | int len, i; |
| 489 | Id lids[64], *sids; |
| 490 | Id id, old; |
| 491 | |
| 492 | if (!ids) |
| 493 | return; |
| 494 | if (!*ids) |
| 495 | { |
| 496 | data_addid(xd, 0); |
| 497 | return; |
| 498 | } |
| 499 | for (len = 0; len < 64 && ids[len]; len++) |
| 500 | { |
| 501 | Id id = ids[len]; |
| 502 | if (needid) |
| 503 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 504 | lids[len] = id; |
| 505 | } |
| 506 | if (ids[len]) |
| 507 | { |
| 508 | for (i = len + 1; ids[i]; i++) |
| 509 | ; |
| 510 | sids = solv_malloc2(i, sizeof(Id)); |
| 511 | memcpy(sids, lids, 64 * sizeof(Id)); |
| 512 | for (; ids[len]; len++) |
| 513 | { |
| 514 | Id id = ids[len]; |
| 515 | if (needid) |
| 516 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 517 | sids[len] = id; |
| 518 | } |
| 519 | } |
| 520 | else |
| 521 | sids = lids; |
| 522 | |
| 523 | /* That bloody solvable:prereqmarker needs to stay in position :-( */ |
| 524 | if (needid) |
| 525 | marker = needid[marker].need; |
| 526 | for (i = 0; i < len; i++) |
| 527 | if (sids[i] == marker) |
| 528 | break; |
| 529 | if (i > 1) |
| 530 | solv_sort(sids, i, sizeof(Id), cmp_ids, 0); |
| 531 | if ((len - i) > 2) |
| 532 | solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0); |
| 533 | |
| 534 | old = 0; |
| 535 | |
| 536 | /* The differencing above produces many runs of ones and twos. I tried |
| 537 | fairly elaborate schemes to RLE those, but they give only very mediocre |
| 538 | improvements in compression, as coding the escapes costs quite some |
| 539 | space. Even if they are coded only as bits in IDs. The best improvement |
| 540 | was about 2.7% for the whole .solv file. It's probably better to |
| 541 | invest some complexity into sharing idarrays, than RLEing. */ |
| 542 | for (i = 0; i < len - 1; i++) |
| 543 | { |
| 544 | id = sids[i]; |
| 545 | /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker, |
| 546 | hence all real differences are offsetted by 1. Otherwise we would |
| 547 | have to handle negative differences, which would cost code space for |
| 548 | the encoding of the sign. We loose the exact mapping of prereq here, |
| 549 | but we know the result, so we can recover from that in the reader. */ |
| 550 | if (id == marker) |
| 551 | id = old = 0; |
| 552 | else |
| 553 | { |
| 554 | id = id - old + 1; |
| 555 | old = sids[i]; |
| 556 | } |
| 557 | /* XXX If difference is zero we have multiple equal elements, |
| 558 | we might want to skip writing them out. */ |
| 559 | data_addideof(xd, id, 0); |
| 560 | } |
| 561 | id = sids[i]; |
| 562 | if (id == marker) |
| 563 | id = 0; |
| 564 | else |
| 565 | id = id - old + 1; |
| 566 | data_addideof(xd, id, 1); |
| 567 | if (sids != lids) |
| 568 | solv_free(sids); |
| 569 | } |
| 570 | |
| 571 | static inline void |
| 572 | data_addblob(struct extdata *xd, unsigned char *blob, int len) |
| 573 | { |
| 574 | xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK4095); |
| 575 | memcpy(xd->buf + xd->len, blob, len); |
| 576 | xd->len += len; |
| 577 | } |
| 578 | |
| 579 | static inline void |
| 580 | data_addu32(struct extdata *xd, unsigned int num) |
| 581 | { |
| 582 | unsigned char d[4]; |
| 583 | d[0] = num >> 24; |
| 584 | d[1] = num >> 16; |
| 585 | d[2] = num >> 8; |
| 586 | d[3] = num; |
| 587 | data_addblob(xd, d, 4); |
| 588 | } |
| 589 | |
| 590 | static Id |
| 591 | putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id) |
| 592 | { |
| 593 | const char *str = stringpool_id2str(ss, id); |
| 594 | id = stringpool_str2id(cbdata->ownspool, str, 1); |
| 595 | if (id >= cbdata->needid[0].map) |
| 596 | { |
| 597 | int oldoff = cbdata->needid[0].map; |
| 598 | int newoff = (id + 1 + NEEDED_BLOCK1023) & ~NEEDED_BLOCK1023; |
| 599 | int nrels = cbdata->repo->pool->nrels; |
| 600 | cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId)); |
| 601 | if (nrels) |
| 602 | memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId)); |
| 603 | memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId)); |
| 604 | cbdata->needid[0].map = newoff; |
| 605 | } |
| 606 | return id; |
| 607 | } |
| 608 | |
| 609 | static Id |
| 610 | putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir) |
| 611 | { |
| 612 | Id compid, parent; |
| 613 | |
| 614 | parent = dirpool_parent(dp, dir); |
| 615 | if (parent) |
| 616 | parent = putinowndirpool(cbdata, data, dp, parent); |
| 617 | compid = dp->dirs[dir]; |
| 618 | if (cbdata->ownspool && compid > 1) |
| 619 | compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid); |
| 620 | return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1); |
| 621 | } |
| 622 | |
| 623 | /* |
| 624 | * collect usage information about the dirs |
| 625 | * 1: dir used, no child of dir used |
| 626 | * 2: dir used as parent of another used dir |
| 627 | */ |
| 628 | static inline void |
| 629 | setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir) |
| 630 | { |
| 631 | if (cbdata->dirused[dir]) |
| 632 | return; |
| 633 | cbdata->dirused[dir] = 1; |
| 634 | while ((dir = dirpool_parent(dp, dir)) != 0) |
| 635 | { |
| 636 | if (cbdata->dirused[dir] == 2) |
| 637 | return; |
| 638 | if (cbdata->dirused[dir]) |
| 639 | { |
| 640 | cbdata->dirused[dir] = 2; |
| 641 | return; |
| 642 | } |
| 643 | cbdata->dirused[dir] = 2; |
| 644 | } |
| 645 | cbdata->dirused[0] = 2; |
| 646 | } |
| 647 | |
| 648 | /* |
| 649 | * pass 1 callback: |
| 650 | * collect key/id/dirid usage information, create needed schemas |
| 651 | */ |
| 652 | static int |
| 653 | repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv) |
| 654 | { |
| 655 | Id id; |
| 656 | int rm; |
| 657 | |
| 658 | if (key->name == REPOSITORY_SOLVABLES) |
| 659 | return SEARCH_NEXT_KEY1; /* we do not want this one */ |
| 660 | |
| 661 | /* hack: ignore some keys, see BUGS */ |
| 662 | if (data->repodataid != data->repo->nrepodata - 1) |
| 663 | if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION) |
| 664 | return SEARCH_NEXT_KEY1; |
| 665 | |
| 666 | rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)]; |
| 667 | if (!rm) |
| 668 | return SEARCH_NEXT_KEY1; /* we do not want this one */ |
| 669 | |
| 670 | /* record key in schema */ |
| 671 | if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0) |
| 672 | && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm)) |
| 673 | *cbdata->sp++ = rm; |
| 674 | |
| 675 | switch(key->type) |
| 676 | { |
| 677 | case REPOKEY_TYPE_ID: |
| 678 | case REPOKEY_TYPE_IDARRAY: |
| 679 | id = kv->id; |
| 680 | if (!ISRELDEP(id)(((id) & 0x80000000) != 0) && cbdata->ownspool && id > 1) |
| 681 | id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id); |
| 682 | incneedid(repo->pool, id, cbdata->needid); |
| 683 | break; |
| 684 | case REPOKEY_TYPE_DIR: |
| 685 | case REPOKEY_TYPE_DIRNUMNUMARRAY: |
| 686 | case REPOKEY_TYPE_DIRSTRARRAY: |
| 687 | id = kv->id; |
| 688 | if (cbdata->owndirpool) |
| 689 | putinowndirpool(cbdata, data, &data->dirpool, id); |
| 690 | else |
| 691 | setdirused(cbdata, &data->dirpool, id); |
| 692 | break; |
| 693 | case REPOKEY_TYPE_FIXARRAY: |
| 694 | if (kv->eof == 0) |
| 695 | { |
| 696 | if (cbdata->oldschema) |
| 697 | { |
| 698 | cbdata->target->error = pool_error(cbdata->repo->pool, -1, "nested fixarray structs not yet implemented"); |
| 699 | return SEARCH_NEXT_KEY1; |
| 700 | } |
| 701 | cbdata->oldschema = cbdata->schema; |
| 702 | cbdata->oldsp = cbdata->sp; |
| 703 | cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id)); |
| 704 | cbdata->sp = cbdata->schema; |
| 705 | } |
| 706 | else if (kv->eof == 1) |
| 707 | { |
| 708 | cbdata->current_sub++; |
| 709 | *cbdata->sp = 0; |
| 710 | cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK31); |
| 711 | cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1); |
| 712 | #if 0 |
| 713 | fprintf(stderrstderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]); |
| 714 | #endif |
| 715 | cbdata->sp = cbdata->schema; |
| 716 | } |
| 717 | else |
| 718 | { |
| 719 | solv_free(cbdata->schema); |
| 720 | cbdata->schema = cbdata->oldschema; |
| 721 | cbdata->sp = cbdata->oldsp; |
| 722 | cbdata->oldsp = cbdata->oldschema = 0; |
| 723 | } |
| 724 | break; |
| 725 | case REPOKEY_TYPE_FLEXARRAY: |
| 726 | if (kv->entry == 0) |
| 727 | { |
| 728 | if (kv->eof != 2) |
| 729 | *cbdata->sp++ = 0; /* mark start */ |
| 730 | } |
| 731 | else |
| 732 | { |
| 733 | /* just finished a schema, rewind */ |
| 734 | Id *sp = cbdata->sp - 1; |
| 735 | *sp = 0; |
| 736 | while (sp[-1]) |
| 737 | sp--; |
| 738 | cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK31); |
| 739 | cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1); |
| 740 | cbdata->sp = kv->eof == 2 ? sp - 1: sp; |
| 741 | } |
| 742 | break; |
| 743 | default: |
| 744 | break; |
| 745 | } |
| 746 | return 0; |
| 747 | } |
| 748 | |
| 749 | static int |
| 750 | repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) |
| 751 | { |
| 752 | struct cbdata *cbdata = vcbdata; |
| 753 | Repo *repo = data->repo; |
| 754 | |
| 755 | #if 0 |
| 756 | if (s) |
| 757 | fprintf(stderrstderr, "solvable %d (%s): key (%d)%s %d\n", s ? s - repo->pool->solvables : 0, s ? pool_id2str(repo->pool, s->name) : "", key->name, pool_id2str(repo->pool, key->name), key->type); |
| 758 | #endif |
| 759 | return repo_write_collect_needed(cbdata, repo, data, key, kv); |
| 760 | } |
| 761 | |
| 762 | |
| 763 | /* |
| 764 | * pass 2 callback: |
| 765 | * encode all of the data into the correct buffers |
| 766 | */ |
| 767 | |
| 768 | static int |
| 769 | repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv) |
| 770 | { |
| 771 | int rm; |
| 772 | Id id; |
| 773 | unsigned int u32; |
| 774 | unsigned char v[4]; |
| 775 | struct extdata *xd; |
| 776 | NeedId *needid; |
| 777 | |
| 778 | if (key->name == REPOSITORY_SOLVABLES) |
| 779 | return SEARCH_NEXT_KEY1; |
| 780 | |
| 781 | /* hack: ignore some keys, see BUGS */ |
| 782 | if (data->repodataid != data->repo->nrepodata - 1) |
| 783 | if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION) |
| 784 | return SEARCH_NEXT_KEY1; |
| 785 | |
| 786 | rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)]; |
| 787 | if (!rm) |
| 788 | return SEARCH_NEXT_KEY1; /* we do not want this one */ |
| 789 | |
| 790 | if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET3) |
| 791 | { |
| 792 | xd = cbdata->extdata + rm; /* vertical buffer */ |
| 793 | if (cbdata->vstart == -1) |
| 794 | cbdata->vstart = xd->len; |
| 795 | } |
| 796 | else |
| 797 | xd = cbdata->extdata + 0; /* incore buffer */ |
| 798 | switch(key->type) |
| 799 | { |
| 800 | case REPOKEY_TYPE_VOID: |
| 801 | case REPOKEY_TYPE_CONSTANT: |
| 802 | case REPOKEY_TYPE_CONSTANTID: |
| 803 | break; |
| 804 | case REPOKEY_TYPE_ID: |
| 805 | id = kv->id; |
| 806 | if (!ISRELDEP(id)(((id) & 0x80000000) != 0) && cbdata->ownspool && id > 1) |
| 807 | id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id); |
| 808 | needid = cbdata->needid; |
| 809 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 810 | data_addid(xd, id); |
| 811 | break; |
| 812 | case REPOKEY_TYPE_IDARRAY: |
| 813 | id = kv->id; |
| 814 | if (!ISRELDEP(id)(((id) & 0x80000000) != 0) && cbdata->ownspool && id > 1) |
| 815 | id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id); |
| 816 | needid = cbdata->needid; |
| 817 | id = needid[ISRELDEP(id)(((id) & 0x80000000) != 0) ? RELOFF(id)(needid[0].map + ((id) ^ 0x80000000)) : id].need; |
| 818 | data_addideof(xd, id, kv->eof); |
| 819 | break; |
| 820 | case REPOKEY_TYPE_STR: |
| 821 | data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1); |
| 822 | break; |
| 823 | case REPOKEY_TYPE_MD5: |
| 824 | data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD516); |
| 825 | break; |
| 826 | case REPOKEY_TYPE_SHA1: |
| 827 | data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA120); |
| 828 | break; |
| 829 | case REPOKEY_TYPE_SHA224: |
| 830 | data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA22428); |
| 831 | break; |
| 832 | case REPOKEY_TYPE_SHA256: |
| 833 | data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA25632); |
| 834 | break; |
| 835 | case REPOKEY_TYPE_SHA384: |
| 836 | data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA38448); |
| 837 | break; |
| 838 | case REPOKEY_TYPE_SHA512: |
| 839 | data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA51264); |
| 840 | break; |
| 841 | case REPOKEY_TYPE_U32: |
| 842 | u32 = kv->num; |
| 843 | v[0] = u32 >> 24; |
| 844 | v[1] = u32 >> 16; |
| 845 | v[2] = u32 >> 8; |
| 846 | v[3] = u32; |
| 847 | data_addblob(xd, v, 4); |
| 848 | break; |
| 849 | case REPOKEY_TYPE_NUM: |
| 850 | data_addid64(xd, kv->num, kv->num2); |
| 851 | break; |
| 852 | case REPOKEY_TYPE_DIR: |
| 853 | id = kv->id; |
| 854 | if (cbdata->owndirpool) |
| 855 | id = putinowndirpool(cbdata, data, &data->dirpool, id); |
| 856 | id = cbdata->dirused[id]; |
| 857 | data_addid(xd, id); |
| 858 | break; |
| 859 | case REPOKEY_TYPE_BINARY: |
| 860 | data_addid(xd, kv->num); |
| 861 | if (kv->num) |
| 862 | data_addblob(xd, (unsigned char *)kv->str, kv->num); |
| 863 | break; |
| 864 | case REPOKEY_TYPE_DIRNUMNUMARRAY: |
| 865 | id = kv->id; |
| 866 | if (cbdata->owndirpool) |
| 867 | id = putinowndirpool(cbdata, data, &data->dirpool, id); |
| 868 | id = cbdata->dirused[id]; |
| 869 | data_addid(xd, id); |
| 870 | data_addid(xd, kv->num); |
| 871 | data_addideof(xd, kv->num2, kv->eof); |
| 872 | break; |
| 873 | case REPOKEY_TYPE_DIRSTRARRAY: |
| 874 | id = kv->id; |
| 875 | if (cbdata->owndirpool) |
| 876 | id = putinowndirpool(cbdata, data, &data->dirpool, id); |
| 877 | id = cbdata->dirused[id]; |
| 878 | if (cbdata->filelistmode > 0) |
| 879 | { |
| 880 | xd->len += data_addideof_len(id) + strlen(kv->str) + 1; |
| 881 | break; |
| 882 | } |
| 883 | data_addideof(xd, id, kv->eof); |
| 884 | data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1); |
| 885 | if (cbdata->filelistmode < 0) |
| 886 | return 0; |
| 887 | break; |
| 888 | case REPOKEY_TYPE_FIXARRAY: |
| 889 | if (kv->eof == 0) |
| 890 | { |
| 891 | if (kv->num) |
| 892 | { |
| 893 | data_addid(xd, kv->num); |
| 894 | data_addid(xd, cbdata->subschemata[cbdata->current_sub]); |
| 895 | #if 0 |
| 896 | fprintf(stderrstderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]); |
| 897 | #endif |
| 898 | } |
| 899 | } |
| 900 | else if (kv->eof == 1) |
| 901 | { |
| 902 | cbdata->current_sub++; |
| 903 | } |
| 904 | break; |
| 905 | case REPOKEY_TYPE_FLEXARRAY: |
| 906 | if (!kv->entry) |
| 907 | data_addid(xd, kv->num); |
| 908 | if (kv->eof != 2) |
| 909 | data_addid(xd, cbdata->subschemata[cbdata->current_sub++]); |
| 910 | if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables) |
| 911 | { |
| 912 | if (xd->len - cbdata->lastlen > cbdata->maxdata) |
| 913 | cbdata->maxdata = xd->len - cbdata->lastlen; |
| 914 | cbdata->lastlen = xd->len; |
| 915 | } |
| 916 | break; |
| 917 | default: |
| 918 | cbdata->target->error = pool_error(cbdata->repo->pool, -1, "unknown type for %d: %d\n", key->name, key->type); |
| 919 | break; |
| 920 | } |
| 921 | if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET3 && kv->eof) |
| 922 | { |
| 923 | /* we can re-use old data in the blob here! */ |
| 924 | data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */ |
| 925 | data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */ |
| 926 | cbdata->vstart = -1; |
| 927 | } |
| 928 | return 0; |
| 929 | } |
| 930 | |
| 931 | static int |
| 932 | repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) |
| 933 | { |
| 934 | struct cbdata *cbdata = vcbdata; |
| 935 | return repo_write_adddata(cbdata, data, key, kv); |
| 936 | } |
| 937 | |
| 938 | /* traverse through directory with first child "dir" */ |
| 939 | static int |
| 940 | traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used) |
| 941 | { |
| 942 | Id sib, child; |
| 943 | Id parent, lastn; |
| 944 | |
| 945 | parent = n; |
| 946 | /* special case for '/', which has to come first */ |
| 947 | if (parent == 1) |
| 948 | dirmap[n++] = 1; |
| 949 | for (sib = dir; sib; sib = dirpool_sibling(dp, sib)) |
| 950 | { |
| 951 | if (used && !used[sib]) |
| 952 | continue; |
| 953 | if (sib == 1 && parent == 1) |
| 954 | continue; /* already did that one above */ |
| 955 | dirmap[n++] = sib; |
| 956 | } |
| 957 | |
| 958 | /* check if our block has some content */ |
| 959 | if (parent == n) |
| 960 | return n - 1; /* nope, drop parent id again */ |
| 961 | |
| 962 | /* now go through all the siblings we just added and |
| 963 | * do recursive calls on them */ |
| 964 | lastn = n; |
| 965 | for (; parent < lastn; parent++) |
| 966 | { |
| 967 | sib = dirmap[parent]; |
| 968 | if (used && used[sib] != 2) /* 2: used as parent */ |
| 969 | continue; |
| 970 | child = dirpool_child(dp, sib); |
| 971 | if (child) |
| 972 | { |
| 973 | dirmap[n++] = -parent; /* start new block */ |
| 974 | n = traverse_dirs(dp, dirmap, n, child, used); |
| 975 | } |
| 976 | } |
| 977 | return n; |
| 978 | } |
| 979 | |
| 980 | static void |
| 981 | write_compressed_page(Repodata *data, unsigned char *page, int len) |
| 982 | { |
| 983 | int clen; |
| 984 | unsigned char cpage[REPOPAGE_BLOBSIZE(1 << 15)]; |
| 985 | |
| 986 | clen = repopagestore_compress_page(page, len, cpage, len - 1); |
| 987 | if (!clen) |
| 988 | { |
| 989 | write_u32(data, len * 2); |
| 990 | write_blob(data, page, len); |
| 991 | } |
| 992 | else |
| 993 | { |
| 994 | write_u32(data, clen * 2 + 1); |
| 995 | write_blob(data, cpage, clen); |
| 996 | } |
| 997 | } |
| 998 | |
| 999 | static Id verticals[] = { |
| 1000 | SOLVABLE_AUTHORS, |
| 1001 | SOLVABLE_DESCRIPTION, |
| 1002 | SOLVABLE_MESSAGEDEL, |
| 1003 | SOLVABLE_MESSAGEINS, |
| 1004 | SOLVABLE_EULA, |
| 1005 | SOLVABLE_DISKUSAGE, |
| 1006 | SOLVABLE_FILELIST, |
| 1007 | SOLVABLE_CHECKSUM, |
| 1008 | DELTA_CHECKSUM, |
| 1009 | DELTA_SEQ_NUM, |
| 1010 | SOLVABLE_PKGID, |
| 1011 | SOLVABLE_HDRID, |
| 1012 | SOLVABLE_LEADSIGID, |
| 1013 | SOLVABLE_CHANGELOG_AUTHOR, |
| 1014 | SOLVABLE_CHANGELOG_TEXT, |
| 1015 | 0 |
| 1016 | }; |
| 1017 | |
| 1018 | static char *languagetags[] = { |
| 1019 | "solvable:summary:", |
| 1020 | "solvable:description:", |
| 1021 | "solvable:messageins:", |
| 1022 | "solvable:messagedel:", |
| 1023 | "solvable:eula:", |
| 1024 | 0 |
| 1025 | }; |
| 1026 | |
| 1027 | int |
| 1028 | repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata) |
| 1029 | { |
| 1030 | const char *keyname; |
| 1031 | int i; |
| 1032 | |
| 1033 | for (i = 0; verticals[i]; i++) |
| 1034 | if (key->name == verticals[i]) |
| 1035 | return KEY_STORAGE_VERTICAL_OFFSET3; |
| 1036 | keyname = pool_id2str(repo->pool, key->name); |
| 1037 | for (i = 0; languagetags[i] != 0; i++) |
| 1038 | if (!strncmp(keyname, languagetags[i], strlen(languagetags[i]))) |
| 1039 | return KEY_STORAGE_VERTICAL_OFFSET3; |
| 1040 | return KEY_STORAGE_INCORE2; |
| 1041 | } |
| 1042 | |
| 1043 | /* |
| 1044 | * return true if the repodata contains the filelist (and just |
| 1045 | * the filelist). The same code is used in the dataiterator. The way |
| 1046 | * it is used is completely wrong, of course, as having the filelist |
| 1047 | * key does not mean it is used for a specific solvable. Nevertheless |
| 1048 | * it is better to have it than to write broken solv files. |
| 1049 | */ |
| 1050 | static inline int |
| 1051 | is_filelist_extension(Repodata *data) |
| 1052 | { |
| 1053 | int j; |
| 1054 | for (j = 1; j < data->nkeys; j++) |
| 1055 | if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) |
| 1056 | return 0; |
| 1057 | return 1; |
| 1058 | } |
| 1059 | |
| 1060 | |
| 1061 | static int |
| 1062 | write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vpage, int lpage) |
| 1063 | { |
| 1064 | unsigned char *dp = xd->buf; |
| 1065 | int l = xd->len; |
| 1066 | while (l) |
| 1067 | { |
| 1068 | int ll = REPOPAGE_BLOBSIZE(1 << 15) - lpage; |
| 1069 | if (l < ll) |
| 1070 | ll = l; |
| 1071 | memcpy(vpage + lpage, dp, ll); |
| 1072 | dp += ll; |
| 1073 | lpage += ll; |
| 1074 | l -= ll; |
| 1075 | if (lpage == REPOPAGE_BLOBSIZE(1 << 15)) |
| 1076 | { |
| 1077 | write_compressed_page(target, vpage, lpage); |
| 1078 | lpage = 0; |
| 1079 | } |
| 1080 | } |
| 1081 | return lpage; |
| 1082 | } |
| 1083 | |
| 1084 | /* |
| 1085 | * Repo |
| 1086 | */ |
| 1087 | |
| 1088 | /* |
| 1089 | * the code works the following way: |
| 1090 | * |
| 1091 | * 1) find which keys should be written |
| 1092 | * 2) collect usage information for keys/ids/dirids, create schema |
| 1093 | * data |
| 1094 | * 3) use usage information to create mapping tables, so that often |
| 1095 | * used ids get a lower number |
| 1096 | * 4) encode data into buffers using the mapping tables |
| 1097 | * 5) write everything to disk |
| 1098 | */ |
| 1099 | int |
| 1100 | repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq) |
| 1101 | { |
| 1102 | Pool *pool = repo->pool; |
| 1103 | int i, j, n, lastfilelistn; |
| 1104 | Solvable *s; |
| 1105 | NeedId *needid; |
| 1106 | int nstrings, nrels; |
| 1107 | unsigned int sizeid; |
| 1108 | unsigned int solv_flags; |
| 1109 | Reldep *ran; |
| 1110 | Id *idarraydata; |
| 1111 | |
| 1112 | Id id, *sp; |
| 1113 | |
| 1114 | Id *dirmap; |
| 1115 | int ndirmap; |
| 1116 | Id *keyused; |
| 1117 | unsigned char *repodataused; |
| 1118 | int anyrepodataused = 0; |
| 1119 | int anysolvableused = 0; |
| 1120 | |
| 1121 | struct cbdata cbdata; |
| 1122 | int clonepool; |
| 1123 | Repokey *key; |
| 1124 | int poolusage, dirpoolusage, idused, dirused; |
| 1125 | int reloff; |
| 1126 | |
| 1127 | Repodata *data, *dirpooldata; |
| 1128 | |
| 1129 | Repodata target; |
| 1130 | |
| 1131 | Stringpool *spool; |
| 1132 | Dirpool *dirpool; |
| 1133 | |
| 1134 | Id mainschema; |
| 1135 | |
| 1136 | struct extdata *xd; |
| 1137 | |
| 1138 | Id type_constantid = REPOKEY_TYPE_CONSTANTID; |
| 1139 | |
| 1140 | |
| 1141 | memset(&cbdata, 0, sizeof(cbdata)); |
| 1142 | cbdata.repo = repo; |
| 1143 | cbdata.target = ⌖ |
| 1144 | |
| 1145 | repodata_initdata(&target, repo, 1); |
| 1146 | |
| 1147 | /* go through all repodata and find the keys we need */ |
| 1148 | /* also unify keys */ |
| 1149 | /* keymapstart - maps repo number to keymap offset */ |
| 1150 | /* keymap - maps repo key to my key, 0 -> not used */ |
| 1151 | |
| 1152 | /* start with all KEY_STORAGE_SOLVABLE ids */ |
| 1153 | |
| 1154 | n = ID_NUM_INTERNAL; |
| 1155 | FOR_REPODATAS(repo, i, data)for (i = 1, data = repo->repodata + i; i < repo->nrepodata ; i++, data++) |
| 1156 | n += data->nkeys; |
| 1157 | cbdata.keymap = solv_calloc(n, sizeof(Id)); |
| 1158 | cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id)); |
| 1159 | repodataused = solv_calloc(repo->nrepodata, 1); |
| 1160 | |
| 1161 | clonepool = 0; |
| 1162 | poolusage = 0; |
| 1163 | |
| 1164 | /* add keys for STORAGE_SOLVABLE */ |
| 1165 | for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++) |
| 1166 | { |
| 1167 | Repokey keyd; |
| 1168 | keyd.name = i; |
| 1169 | if (i < SOLVABLE_PROVIDES) |
| 1170 | keyd.type = REPOKEY_TYPE_ID; |
| 1171 | else if (i < RPM_RPMDBID) |
| 1172 | keyd.type = REPOKEY_TYPE_REL_IDARRAY; |
| 1173 | else |
| 1174 | keyd.type = REPOKEY_TYPE_NUM; |
| 1175 | keyd.size = 0; |
| 1176 | keyd.storage = KEY_STORAGE_SOLVABLE1; |
| 1177 | if (keyfilter) |
| 1178 | { |
| 1179 | keyd.storage = keyfilter(repo, &keyd, kfdata); |
| 1180 | if (keyd.storage == KEY_STORAGE_DROPPED0) |
| 1181 | continue; |
| 1182 | keyd.storage = KEY_STORAGE_SOLVABLE1; |
| 1183 | } |
| 1184 | poolusage = 1; |
| 1185 | clonepool = 1; |
| 1186 | cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1); |
| 1187 | } |
| 1188 | |
| 1189 | if (repo->nsolvables) |
| 1190 | { |
| 1191 | Repokey keyd; |
| 1192 | keyd.name = REPOSITORY_SOLVABLES; |
| 1193 | keyd.type = REPOKEY_TYPE_FLEXARRAY; |
| 1194 | keyd.size = 0; |
| 1195 | keyd.storage = KEY_STORAGE_INCORE2; |
| 1196 | cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1); |
| 1197 | } |
| 1198 | |
| 1199 | dirpoolusage = 0; |
| 1200 | |
| 1201 | spool = 0; |
| 1202 | dirpool = 0; |
| 1203 | dirpooldata = 0; |
| 1204 | n = ID_NUM_INTERNAL; |
| 1205 | lastfilelistn = 0; |
| 1206 | FOR_REPODATAS(repo, i, data)for (i = 1, data = repo->repodata + i; i < repo->nrepodata ; i++, data++) |
| 1207 | { |
| 1208 | cbdata.keymapstart[i] = n; |
| 1209 | cbdata.keymap[n++] = 0; /* key 0 */ |
| 1210 | idused = 0; |
| 1211 | dirused = 0; |
| 1212 | if (keyfilter) |
| 1213 | { |
| 1214 | Repokey keyd; |
| 1215 | /* check if we want this repodata */ |
| 1216 | memset(&keyd, 0, sizeof(keyd)); |
| 1217 | keyd.name = 1; |
| 1218 | keyd.type = 1; |
| 1219 | keyd.size = i; |
| 1220 | if (keyfilter(repo, &keyd, kfdata) == -1) |
| 1221 | continue; |
| 1222 | } |
| 1223 | for (j = 1; j < data->nkeys; j++, n++) |
| 1224 | { |
| 1225 | key = data->keys + j; |
| 1226 | if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY) |
| 1227 | { |
| 1228 | cbdata.keymap[n] = cbdata.keymap[key->name]; |
| 1229 | continue; |
| 1230 | } |
| 1231 | if (key->type == REPOKEY_TYPE_DELETED) |
| 1232 | { |
| 1233 | cbdata.keymap[n] = 0; |
| 1234 | continue; |
| 1235 | } |
| 1236 | if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool) |
| 1237 | { |
| 1238 | Repokey keyd = *key; |
| 1239 | keyd.size = repodata_globalize_id(data, key->size, 1); |
| 1240 | id = repodata_key2id(&target, &keyd, 0); |
| 1241 | } |
| 1242 | else |
| 1243 | id = repodata_key2id(&target, key, 0); |
| 1244 | if (!id) |
| 1245 | { |
| 1246 | Repokey keyd = *key; |
| 1247 | keyd.storage = KEY_STORAGE_INCORE2; |
| 1248 | if (keyd.type == REPOKEY_TYPE_CONSTANTID) |
| 1249 | keyd.size = repodata_globalize_id(data, key->size, 1); |
| 1250 | else if (keyd.type != REPOKEY_TYPE_CONSTANT) |
| 1251 | keyd.size = 0; |
| 1252 | if (keyfilter) |
| 1253 | { |
| 1254 | keyd.storage = keyfilter(repo, &keyd, kfdata); |
| 1255 | if (keyd.storage == KEY_STORAGE_DROPPED0) |
| 1256 | { |
| 1257 | cbdata.keymap[n] = 0; |
| 1258 | continue; |
| 1259 | } |
| 1260 | } |
| 1261 | id = repodata_key2id(&target, &keyd, 1); |
| 1262 | } |
| 1263 | cbdata.keymap[n] = id; |
| 1264 | /* load repodata if not already loaded */ |
| 1265 | if (data->state == REPODATA_STUB1) |
| 1266 | { |
| 1267 | if (data->loadcallback) |
| 1268 | data->loadcallback(data); |
| 1269 | else |
| 1270 | data->state = REPODATA_ERROR2; |
| 1271 | if (data->state != REPODATA_ERROR2) |
| 1272 | { |
| 1273 | /* redo this repodata! */ |
| 1274 | j = 0; |
| 1275 | n = cbdata.keymapstart[i]; |
| 1276 | continue; |
| 1277 | } |
| 1278 | } |
| 1279 | if (data->state == REPODATA_ERROR2) |
| 1280 | { |
| 1281 | /* too bad! */ |
| 1282 | cbdata.keymap[n] = 0; |
| 1283 | continue; |
| 1284 | } |
| 1285 | |
| 1286 | repodataused[i] = 1; |
| 1287 | anyrepodataused = 1; |
| 1288 | if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID || |
| 1289 | key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY) |
| 1290 | idused = 1; |
| 1291 | else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY) |
| 1292 | { |
| 1293 | idused = 1; /* dirs also use ids */ |
| 1294 | dirused = 1; |
| 1295 | } |
| 1296 | if (key->type == REPOKEY_TYPE_DIRSTRARRAY && key->name == SOLVABLE_FILELIST) |
| 1297 | { |
| 1298 | /* is this a file list extension */ |
| 1299 | if (is_filelist_extension(data)) |
| 1300 | { |
| 1301 | /* hmm, we have a file list extension. Kill filelist of other repodata. |
| 1302 | * XXX: this is wrong, as the extension does not need to cover all |
| 1303 | * solvables of the other repodata */ |
| 1304 | if (lastfilelistn) |
| 1305 | cbdata.keymap[lastfilelistn] = 0; |
| 1306 | } |
| 1307 | else |
| 1308 | lastfilelistn = n; |
| 1309 | } |
| 1310 | } |
| 1311 | if (idused) |
| 1312 | { |
| 1313 | if (data->localpool) |
| 1314 | { |
| 1315 | if (poolusage) |
| 1316 | poolusage = 3; /* need own pool */ |
| 1317 | else |
| 1318 | { |
| 1319 | poolusage = 2; |
| 1320 | spool = &data->spool; |
| 1321 | } |
| 1322 | } |
| 1323 | else |
| 1324 | { |
| 1325 | if (poolusage == 0) |
| 1326 | poolusage = 1; |
| 1327 | else if (poolusage != 1) |
| 1328 | poolusage = 3; /* need own pool */ |
| 1329 | } |
| 1330 | } |
| 1331 | if (dirused) |
| 1332 | { |
| 1333 | if (dirpoolusage) |
| 1334 | dirpoolusage = 3; /* need own dirpool */ |
| 1335 | else |
| 1336 | { |
| 1337 | dirpoolusage = 2; |
| 1338 | dirpool = &data->dirpool; |
| 1339 | dirpooldata = data; |
| 1340 | } |
| 1341 | } |
| 1342 | } |
| 1343 | cbdata.nkeymap = n; |
| 1344 | |
| 1345 | /* 0: no pool needed at all */ |
| 1346 | /* 1: use global pool */ |
| 1347 | /* 2: use repodata local pool */ |
| 1348 | /* 3: need own pool */ |
| 1349 | if (poolusage == 3) |
| 1350 | { |
| 1351 | spool = &target.spool; |
| 1352 | /* hack: reuse global pool data so we don't have to map pool ids */ |
| 1353 | if (clonepool) |
| 1354 | { |
| 1355 | stringpool_free(spool); |
| 1356 | stringpool_clone(spool, &pool->ss); |
| 1357 | } |
| 1358 | cbdata.ownspool = spool; |
| 1359 | } |
| 1360 | else if (poolusage == 0 || poolusage == 1) |
| 1361 | { |
| 1362 | poolusage = 1; |
| 1363 | spool = &pool->ss; |
| 1364 | } |
| 1365 | |
| 1366 | if (dirpoolusage == 3) |
| 1367 | { |
| 1368 | dirpool = &target.dirpool; |
| 1369 | dirpooldata = 0; |
| 1370 | cbdata.owndirpool = dirpool; |
| 1371 | } |
| 1372 | else if (dirpool) |
| 1373 | cbdata.dirused = solv_calloc(dirpool->ndirs, sizeof(Id)); |
| 1374 | |
| 1375 | |
| 1376 | /********************************************************************/ |
| 1377 | #if 0 |
| 1378 | fprintf(stderrstderr, "poolusage: %d\n", poolusage); |
| 1379 | fprintf(stderrstderr, "dirpoolusage: %d\n", dirpoolusage); |
| 1380 | fprintf(stderrstderr, "nkeys: %d\n", target.nkeys); |
| 1381 | for (i = 1; i < target.nkeys; i++) |
| 1382 | fprintf(stderrstderr, " %2d: %s[%d] %d %d %d\n", i, pool_id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage); |
| 1383 | #endif |
| 1384 | |
| 1385 | /* copy keys if requested */ |
| 1386 | if (keyq) |
| 1387 | { |
| 1388 | queue_empty(keyq); |
| 1389 | for (i = 1; i < target.nkeys; i++) |
| 1390 | queue_push2(keyq, target.keys[i].name, target.keys[i].type); |
| 1391 | } |
| 1392 | |
| 1393 | if (poolusage > 1) |
| 1394 | { |
| 1395 | /* put all the keys we need in our string pool */ |
| 1396 | /* put mapped ids right into target.keys */ |
| 1397 | for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++) |
| 1398 | { |
| 1399 | key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1); |
| 1400 | if (key->type == REPOKEY_TYPE_CONSTANTID) |
| 1401 | { |
| 1402 | key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1); |
| 1403 | type_constantid = key->type; |
| 1404 | key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1); |
| 1405 | } |
| 1406 | else |
| 1407 | key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1); |
| 1408 | } |
| 1409 | if (poolusage == 2) |
| 1410 | stringpool_freehash(spool); /* free some mem */ |
| 1411 | } |
| 1412 | |
| 1413 | |
| 1414 | /********************************************************************/ |
| 1415 | |
| 1416 | /* set needed count of all strings and rels, |
| 1417 | * find which keys are used in the solvables |
| 1418 | * put all strings in own spool |
| 1419 | */ |
| 1420 | |
| 1421 | reloff = spool->nstrings; |
| 1422 | if (poolusage == 3) |
| 1423 | reloff = (reloff + NEEDED_BLOCK1023) & ~NEEDED_BLOCK1023; |
| 1424 | |
| 1425 | needid = calloc(reloff + pool->nrels, sizeof(*needid)); |
| 1426 | needid[0].map = reloff; |
| 1427 | |
| 1428 | cbdata.needid = needid; |
| 1429 | cbdata.schema = solv_calloc(target.nkeys, sizeof(Id)); |
| 1430 | cbdata.sp = cbdata.schema; |
| 1431 | cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id)); |
| 1432 | |
| 1433 | /* create main schema */ |
| 1434 | cbdata.sp = cbdata.schema; |
| 1435 | /* collect all other data from all repodatas */ |
| 1436 | /* XXX: merge arrays of equal keys? */ |
| 1437 | FOR_REPODATAS(repo, j, data)for (j = 1, data = repo->repodata + j; j < repo->nrepodata ; j++, data++) |
| 1438 | { |
| 1439 | if (!repodataused[j]) |
| 1440 | continue; |
| 1441 | repodata_search(data, SOLVID_META-1, 0, SEARCH_SUB(1<<9)|SEARCH_ARRAYSENTINEL(1<<10), repo_write_cb_needed, &cbdata); |
| 1442 | } |
| 1443 | sp = cbdata.sp; |
| 1444 | /* add solvables if needed (may revert later) */ |
| 1445 | if (repo->nsolvables) |
| 1446 | { |
| 1447 | *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES]; |
| 1448 | target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++; |
| 1449 | } |
| 1450 | *sp = 0; |
| 1451 | mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1); |
| 1452 | |
| 1453 | idarraydata = repo->idarraydata; |
| 1454 | |
| 1455 | anysolvableused = 0; |
| 1456 | cbdata.doingsolvables = 1; |
| 1457 | for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) |
| 1458 | { |
| 1459 | if (s->repo != repo) |
| 1460 | continue; |
| 1461 | |
| 1462 | /* set schema info, keep in sync with further down */ |
| 1463 | sp = cbdata.schema; |
| 1464 | if (cbdata.keymap[SOLVABLE_NAME]) |
| 1465 | { |
| 1466 | *sp++ = cbdata.keymap[SOLVABLE_NAME]; |
| 1467 | needid[s->name].need++; |
| 1468 | } |
| 1469 | if (cbdata.keymap[SOLVABLE_ARCH]) |
| 1470 | { |
| 1471 | *sp++ = cbdata.keymap[SOLVABLE_ARCH]; |
| 1472 | needid[s->arch].need++; |
| 1473 | } |
| 1474 | if (cbdata.keymap[SOLVABLE_EVR]) |
| 1475 | { |
| 1476 | *sp++ = cbdata.keymap[SOLVABLE_EVR]; |
| 1477 | needid[s->evr].need++; |
| 1478 | } |
| 1479 | if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR]) |
| 1480 | { |
| 1481 | *sp++ = cbdata.keymap[SOLVABLE_VENDOR]; |
| 1482 | needid[s->vendor].need++; |
| 1483 | } |
| 1484 | if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES]) |
| 1485 | { |
| 1486 | *sp++ = cbdata.keymap[SOLVABLE_PROVIDES]; |
| 1487 | target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid); |
| 1488 | } |
| 1489 | if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES]) |
| 1490 | { |
| 1491 | *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES]; |
| 1492 | target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid); |
| 1493 | } |
| 1494 | if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS]) |
| 1495 | { |
| 1496 | *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS]; |
| 1497 | target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid); |
| 1498 | } |
| 1499 | if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES]) |
| 1500 | { |
| 1501 | *sp++ = cbdata.keymap[SOLVABLE_REQUIRES]; |
| 1502 | target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid); |
| 1503 | } |
| 1504 | if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS]) |
| 1505 | { |
| 1506 | *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS]; |
| 1507 | target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid); |
| 1508 | } |
| 1509 | if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS]) |
| 1510 | { |
| 1511 | *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS]; |
| 1512 | target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid); |
| 1513 | } |
| 1514 | if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS]) |
| 1515 | { |
| 1516 | *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS]; |
| 1517 | target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid); |
| 1518 | } |
| 1519 | if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES]) |
| 1520 | { |
| 1521 | *sp++ = cbdata.keymap[SOLVABLE_ENHANCES]; |
| 1522 | target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid); |
| 1523 | } |
| 1524 | if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID]) |
| 1525 | { |
| 1526 | *sp++ = cbdata.keymap[RPM_RPMDBID]; |
| 1527 | target.keys[cbdata.keymap[RPM_RPMDBID]].size++; |
| 1528 | } |
| 1529 | cbdata.sp = sp; |
| 1530 | |
| 1531 | if (anyrepodataused) |
| 1532 | { |
| 1533 | FOR_REPODATAS(repo, j, data)for (j = 1, data = repo->repodata + j; j < repo->nrepodata ; j++, data++) |
| 1534 | { |
| 1535 | if (!repodataused[j]) |
| 1536 | continue; |
| 1537 | if (i < data->start || i >= data->end) |
| 1538 | continue; |
| 1539 | repodata_search(data, i, 0, SEARCH_SUB(1<<9)|SEARCH_ARRAYSENTINEL(1<<10), repo_write_cb_needed, &cbdata); |
| 1540 | needid = cbdata.needid; |
| 1541 | } |
| 1542 | } |
| 1543 | *cbdata.sp = 0; |
| 1544 | cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1); |
| 1545 | if (cbdata.solvschemata[n]) |
| 1546 | anysolvableused = 1; |
| 1547 | n++; |
| 1548 | } |
| 1549 | cbdata.doingsolvables = 0; |
| 1550 | assert(n == repo->nsolvables)({ if (n == repo->nsolvables) ; else __assert_fail ("n == repo->nsolvables" , "/home/brain/Projects/upstream/libsolv/src/repo_write.c", 1550 , __PRETTY_FUNCTION__); }); |
| 1551 | |
| 1552 | if (repo->nsolvables && !anysolvableused) |
| 1553 | { |
| 1554 | /* strip off solvable from the main schema */ |
| 1555 | target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0; |
| 1556 | sp = cbdata.schema; |
| 1557 | for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++) |
| 1558 | { |
| 1559 | *sp = target.schemadata[target.schemata[mainschema] + i]; |
| 1560 | if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES]) |
| 1561 | sp++; |
| 1562 | } |
| 1563 | assert(target.schemadatalen == target.schemata[mainschema] + i + 1)({ if (target.schemadatalen == target.schemata[mainschema] + i + 1) ; else __assert_fail ("target.schemadatalen == target.schemata[mainschema] + i + 1" , "/home/brain/Projects/upstream/libsolv/src/repo_write.c", 1563 , __PRETTY_FUNCTION__); }); |
| 1564 | *sp = 0; |
| 1565 | target.schemadatalen = target.schemata[mainschema]; |
| 1566 | target.nschemata--; |
| 1567 | repodata_free_schemahash(&target); |
| 1568 | mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1); |
| 1569 | } |
| 1570 | |
| 1571 | /********************************************************************/ |
| 1572 | |
| 1573 | /* remove unused keys */ |
| 1574 | keyused = solv_calloc(target.nkeys, sizeof(Id)); |
| 1575 | for (i = 1; i < (int)target.schemadatalen; i++) |
| 1576 | keyused[target.schemadata[i]] = 1; |
| 1577 | keyused[0] = 0; |
| 1578 | for (n = i = 1; i < target.nkeys; i++) |
| 1579 | { |
| 1580 | if (!keyused[i]) |
| 1581 | continue; |
| 1582 | keyused[i] = n; |
| 1583 | if (i != n) |
| 1584 | { |
| 1585 | target.keys[n] = target.keys[i]; |
| 1586 | if (keyq) |
| 1587 | { |
| 1588 | keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2]; |
| 1589 | keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1]; |
| 1590 | } |
| 1591 | } |
| 1592 | n++; |
| 1593 | } |
| 1594 | target.nkeys = n; |
| 1595 | if (keyq) |
| 1596 | queue_truncate(keyq, 2 * n - 2); |
| 1597 | |
| 1598 | /* update schema data to the new key ids */ |
| 1599 | for (i = 1; i < (int)target.schemadatalen; i++) |
| 1600 | target.schemadata[i] = keyused[target.schemadata[i]]; |
| 1601 | /* update keymap to the new key ids */ |
| 1602 | for (i = 0; i < cbdata.nkeymap; i++) |
| 1603 | cbdata.keymap[i] = keyused[cbdata.keymap[i]]; |
| 1604 | keyused = solv_free(keyused); |
Value stored to 'keyused' is never read | |
| 1605 | |
| 1606 | /* increment needid of the used keys, they are already mapped to |
| 1607 | * the correct string pool */ |
| 1608 | for (i = 1; i < target.nkeys; i++) |
| 1609 | { |
| 1610 | if (target.keys[i].type == type_constantid) |
| 1611 | needid[target.keys[i].size].need++; |
| 1612 | needid[target.keys[i].name].need++; |
| 1613 | needid[target.keys[i].type].need++; |
| 1614 | } |
| 1615 | |
| 1616 | /********************************************************************/ |
| 1617 | |
| 1618 | if (dirpool && cbdata.dirused && !cbdata.dirused[0]) |
| 1619 | { |
| 1620 | /* no dirs used at all */ |
| 1621 | cbdata.dirused = solv_free(cbdata.dirused); |
| 1622 | dirpool = 0; |
| 1623 | } |
| 1624 | |
| 1625 | /* increment need id for used dir components */ |
| 1626 | if (dirpool) |
| 1627 | { |
| 1628 | /* if we have own dirpool, all entries in it are used. |
| 1629 | also, all comp ids are already mapped by putinowndirpool(), |
| 1630 | so we can simply increment needid. |
| 1631 | (owndirpool != 0, dirused == 0, dirpooldata == 0) */ |
| 1632 | /* else we re-use a dirpool of repodata "dirpooldata". |
| 1633 | dirused tells us which of the ids are used. |
| 1634 | we need to map comp ids if we generate a new pool. |
| 1635 | (owndirpool == 0, dirused != 0, dirpooldata != 0) */ |
| 1636 | for (i = 1; i < dirpool->ndirs; i++) |
| 1637 | { |
| 1638 | #if 0 |
| 1639 | fprintf(stderrstderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); |
| 1640 | #endif |
| 1641 | if (cbdata.dirused && !cbdata.dirused[i]) |
| 1642 | continue; |
| 1643 | id = dirpool->dirs[i]; |
| 1644 | if (id <= 0) |
| 1645 | continue; |
| 1646 | if (dirpooldata && cbdata.ownspool && id > 1) |
| 1647 | { |
| 1648 | id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id); |
| 1649 | needid = cbdata.needid; |
| 1650 | } |
| 1651 | needid[id].need++; |
| 1652 | } |
| 1653 | } |
| 1654 | |
| 1655 | |
| 1656 | /********************************************************************/ |
| 1657 | |
| 1658 | /* |
| 1659 | * create mapping table, new keys are sorted by needid[].need |
| 1660 | * |
| 1661 | * needid[key].need : old key -> new key |
| 1662 | * needid[key].map : new key -> old key |
| 1663 | */ |
| 1664 | |
| 1665 | /* zero out id 0 and rel 0 just in case */ |
| 1666 | reloff = needid[0].map; |
| 1667 | needid[0].need = 0; |
| 1668 | needid[reloff].need = 0; |
| 1669 | |
| 1670 | for (i = 1; i < reloff + pool->nrels; i++) |
| 1671 | needid[i].map = i; |
| 1672 | |
| 1673 | #if 0 |
| 1674 | solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool); |
| 1675 | #else |
| 1676 | /* make first entry '' */ |
| 1677 | needid[1].need = 1; |
| 1678 | solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool); |
| 1679 | #endif |
| 1680 | solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0); |
| 1681 | /* now needid is in new order, needid[newid].map -> oldid */ |
| 1682 | |
| 1683 | /* calculate string space size, also zero out needid[].need */ |
| 1684 | sizeid = 0; |
| 1685 | for (i = 1; i < reloff; i++) |
| 1686 | { |
| 1687 | if (!needid[i].need) |
| 1688 | break; /* as we have sorted, every entry after this also has need == 0 */ |
| 1689 | needid[i].need = 0; |
| 1690 | sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1; |
| 1691 | } |
| 1692 | nstrings = i; /* our new string id end */ |
| 1693 | |
| 1694 | /* make needid[oldid].need point to newid */ |
| 1695 | for (i = 1; i < nstrings; i++) |
| 1696 | needid[needid[i].map].need = i; |
| 1697 | |
| 1698 | /* same as above for relations */ |
| 1699 | for (i = 0; i < pool->nrels; i++) |
| 1700 | { |
| 1701 | if (!needid[reloff + i].need) |
| 1702 | break; |
| 1703 | needid[reloff + i].need = 0; |
| 1704 | } |
| 1705 | nrels = i; /* our new rel id end */ |
| 1706 | |
| 1707 | for (i = 0; i < nrels; i++) |
| 1708 | needid[needid[reloff + i].map].need = nstrings + i; |
| 1709 | |
| 1710 | /* now we have: needid[oldid].need -> newid |
| 1711 | needid[newid].map -> oldid |
| 1712 | both for strings and relations */ |
| 1713 | |
| 1714 | |
| 1715 | /********************************************************************/ |
| 1716 | |
| 1717 | ndirmap = 0; |
| 1718 | dirmap = 0; |
| 1719 | if (dirpool) |
| 1720 | { |
| 1721 | /* create our new target directory structure by traversing through all |
| 1722 | * used dirs. This will concatenate blocks with the same parent |
| 1723 | * directory into single blocks. |
| 1724 | * Instead of components, traverse_dirs stores the old dirids, |
| 1725 | * we will change this in the second step below */ |
| 1726 | /* (dirpooldata and dirused are 0 if we have our own dirpool) */ |
| 1727 | if (cbdata.dirused && !cbdata.dirused[1]) |
| 1728 | cbdata.dirused[1] = 1; /* always want / entry */ |
| 1729 | dirmap = solv_calloc(dirpool->ndirs, sizeof(Id)); |
| 1730 | dirmap[0] = 0; |
| 1731 | ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused); |
| 1732 | |
| 1733 | /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */ |
| 1734 | /* change dirmap so that it maps from "new dirid" to "new compid" */ |
| 1735 | if (!cbdata.dirused) |
| 1736 | cbdata.dirused = solv_malloc2(dirpool->ndirs, sizeof(Id)); |
| 1737 | memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id)); |
| 1738 | for (i = 1; i < ndirmap; i++) |
| 1739 | { |
| 1740 | if (dirmap[i] <= 0) |
| 1741 | continue; |
| 1742 | cbdata.dirused[dirmap[i]] = i; |
| 1743 | id = dirpool->dirs[dirmap[i]]; |
| 1744 | if (dirpooldata && cbdata.ownspool && id > 1) |
| 1745 | id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id); |
| 1746 | dirmap[i] = needid[id].need; |
| 1747 | } |
| 1748 | /* now the new target directory structure is complete (dirmap), and we have |
| 1749 | * dirused[olddirid] -> newdirid */ |
| 1750 | } |
| 1751 | |
| 1752 | /********************************************************************/ |
| 1753 | |
| 1754 | /* collect all data |
| 1755 | * we use extdata[0] for incore data and extdata[keyid] for vertical data |
| 1756 | */ |
| 1757 | |
| 1758 | cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata)); |
| 1759 | |
| 1760 | xd = cbdata.extdata; |
| 1761 | cbdata.current_sub = 0; |
| 1762 | /* add main schema */ |
| 1763 | cbdata.lastlen = 0; |
| 1764 | data_addid(xd, mainschema); |
| 1765 | |
| 1766 | #if 1 |
| 1767 | FOR_REPODATAS(repo, j, data)for (j = 1, data = repo->repodata + j; j < repo->nrepodata ; j++, data++) |
| 1768 | { |
| 1769 | if (!repodataused[j]) |
| 1770 | continue; |
| 1771 | repodata_search(data, SOLVID_META-1, 0, SEARCH_SUB(1<<9)|SEARCH_ARRAYSENTINEL(1<<10), repo_write_cb_adddata, &cbdata); |
| 1772 | } |
| 1773 | #endif |
| 1774 | |
| 1775 | if (xd->len - cbdata.lastlen > cbdata.maxdata) |
| 1776 | cbdata.maxdata = xd->len - cbdata.lastlen; |
| 1777 | cbdata.lastlen = xd->len; |
| 1778 | |
| 1779 | if (anysolvableused) |
| 1780 | { |
| 1781 | data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */ |
| 1782 | cbdata.doingsolvables = 1; |
| 1783 | |
| 1784 | /* check if we can do the special filelist memory optimization */ |
| 1785 | if (anyrepodataused) |
| 1786 | { |
| 1787 | for (i = 1; i < target.nkeys; i++) |
| 1788 | if (target.keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET3) |
| 1789 | cbdata.filelistmode |= cbdata.filelistmode == 0 && target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY ? 1 : 2; |
| 1790 | else if (target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY) |
| 1791 | cbdata.filelistmode = 2; |
| 1792 | if (cbdata.filelistmode != 1) |
| 1793 | cbdata.filelistmode = 0; |
| 1794 | } |
| 1795 | |
| 1796 | for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) |
| 1797 | { |
| 1798 | if (s->repo != repo) |
| 1799 | continue; |
| 1800 | data_addid(xd, cbdata.solvschemata[n]); |
| 1801 | if (cbdata.keymap[SOLVABLE_NAME]) |
| 1802 | data_addid(xd, needid[s->name].need); |
| 1803 | if (cbdata.keymap[SOLVABLE_ARCH]) |
| 1804 | data_addid(xd, needid[s->arch].need); |
| 1805 | if (cbdata.keymap[SOLVABLE_EVR]) |
| 1806 | data_addid(xd, needid[s->evr].need); |
| 1807 | if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR]) |
| 1808 | data_addid(xd, needid[s->vendor].need); |
| 1809 | if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES]) |
| 1810 | data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER); |
| 1811 | if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES]) |
| 1812 | data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0); |
| 1813 | if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS]) |
| 1814 | data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0); |
| 1815 | if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES]) |
| 1816 | data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER); |
| 1817 | if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS]) |
| 1818 | data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0); |
| 1819 | if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS]) |
| 1820 | data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0); |
| 1821 | if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS]) |
| 1822 | data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0); |
| 1823 | if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES]) |
| 1824 | data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0); |
| 1825 | if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID]) |
| 1826 | data_addid(xd, repo->rpmdbid[i - repo->start]); |
| 1827 | if (anyrepodataused) |
| 1828 | { |
| 1829 | cbdata.vstart = -1; |
| 1830 | FOR_REPODATAS(repo, j, data)for (j = 1, data = repo->repodata + j; j < repo->nrepodata ; j++, data++) |
| 1831 | { |
| 1832 | if (!repodataused[j]) |
| 1833 | continue; |
| 1834 | if (i < data->start || i >= data->end) |
| 1835 | continue; |
| 1836 | repodata_search(data, i, 0, SEARCH_SUB(1<<9)|SEARCH_ARRAYSENTINEL(1<<10), repo_write_cb_adddata, &cbdata); |
| 1837 | } |
| 1838 | } |
| 1839 | if (xd->len - cbdata.lastlen > cbdata.maxdata) |
| 1840 | cbdata.maxdata = xd->len - cbdata.lastlen; |
| 1841 | cbdata.lastlen = xd->len; |
| 1842 | n++; |
| 1843 | } |
| 1844 | cbdata.doingsolvables = 0; |
| 1845 | } |
| 1846 | |
| 1847 | assert(cbdata.current_sub == cbdata.nsubschemata)({ if (cbdata.current_sub == cbdata.nsubschemata) ; else __assert_fail ("cbdata.current_sub == cbdata.nsubschemata", "/home/brain/Projects/upstream/libsolv/src/repo_write.c" , 1847, __PRETTY_FUNCTION__); }); |
| 1848 | if (cbdata.subschemata) |
| 1849 | { |
| 1850 | cbdata.subschemata = solv_free(cbdata.subschemata); |
| 1851 | cbdata.nsubschemata = 0; |
| 1852 | } |
| 1853 | |
| 1854 | /********************************************************************/ |
| 1855 | |
| 1856 | target.fp = fp; |
| 1857 | |
| 1858 | /* write header */ |
| 1859 | |
| 1860 | /* write file header */ |
| 1861 | write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V'); |
| 1862 | write_u32(&target, SOLV_VERSION_88); |
| 1863 | |
| 1864 | |
| 1865 | /* write counts */ |
| 1866 | write_u32(&target, nstrings); |
| 1867 | write_u32(&target, nrels); |
| 1868 | write_u32(&target, ndirmap); |
| 1869 | write_u32(&target, anysolvableused ? repo->nsolvables : 0); |
| 1870 | write_u32(&target, target.nkeys); |
| 1871 | write_u32(&target, target.nschemata); |
| 1872 | solv_flags = 0; |
| 1873 | solv_flags |= SOLV_FLAG_PREFIX_POOL4; |
| 1874 | solv_flags |= SOLV_FLAG_SIZE_BYTES8; |
| 1875 | write_u32(&target, solv_flags); |
| 1876 | |
| 1877 | if (nstrings) |
| 1878 | { |
| 1879 | /* |
| 1880 | * calculate prefix encoding of the strings |
| 1881 | */ |
| 1882 | unsigned char *prefixcomp = solv_malloc(nstrings); |
| 1883 | unsigned int compsum = 0; |
| 1884 | char *old_str = ""; |
| 1885 | |
| 1886 | prefixcomp[0] = 0; |
| 1887 | for (i = 1; i < nstrings; i++) |
| 1888 | { |
| 1889 | char *str = spool->stringspace + spool->strings[needid[i].map]; |
| 1890 | int same; |
| 1891 | for (same = 0; same < 255; same++) |
| 1892 | if (!old_str[same] || old_str[same] != str[same]) |
| 1893 | break; |
| 1894 | prefixcomp[i] = same; |
| 1895 | compsum += same; |
| 1896 | old_str = str; |
| 1897 | } |
| 1898 | |
| 1899 | /* |
| 1900 | * write strings |
| 1901 | */ |
| 1902 | write_u32(&target, sizeid); |
| 1903 | /* we save compsum bytes but need 1 extra byte for every string */ |
| 1904 | write_u32(&target, sizeid + nstrings - 1 - compsum); |
| 1905 | for (i = 1; i < nstrings; i++) |
| 1906 | { |
| 1907 | char *str = spool->stringspace + spool->strings[needid[i].map]; |
| 1908 | write_u8(&target, prefixcomp[i]); |
| 1909 | write_str(&target, str + prefixcomp[i]); |
| 1910 | } |
| 1911 | solv_free(prefixcomp); |
| 1912 | } |
| 1913 | else |
| 1914 | { |
| 1915 | write_u32(&target, 0); |
| 1916 | write_u32(&target, 0); |
| 1917 | } |
| 1918 | |
| 1919 | /* |
| 1920 | * write RelDeps |
| 1921 | */ |
| 1922 | for (i = 0; i < nrels; i++) |
| 1923 | { |
| 1924 | ran = pool->rels + (needid[reloff + i].map - reloff); |
| 1925 | write_id(&target, needid[ISRELDEP(ran->name)(((ran->name) & 0x80000000) != 0) ? RELOFF(ran->name)(needid[0].map + ((ran->name) ^ 0x80000000)) : ran->name].need); |
| 1926 | write_id(&target, needid[ISRELDEP(ran->evr)(((ran->evr) & 0x80000000) != 0) ? RELOFF(ran->evr)(needid[0].map + ((ran->evr) ^ 0x80000000)) : ran->evr].need); |
| 1927 | write_u8(&target, ran->flags); |
| 1928 | } |
| 1929 | |
| 1930 | /* |
| 1931 | * write dirs (skip both root and / entry) |
| 1932 | */ |
| 1933 | for (i = 2; i < ndirmap; i++) |
| 1934 | { |
| 1935 | if (dirmap[i] > 0) |
| 1936 | write_id(&target, dirmap[i]); |
| 1937 | else |
| 1938 | write_id(&target, nstrings - dirmap[i]); |
| 1939 | } |
| 1940 | solv_free(dirmap); |
| 1941 | |
| 1942 | /* |
| 1943 | * write keys |
| 1944 | */ |
| 1945 | for (i = 1; i < target.nkeys; i++) |
| 1946 | { |
| 1947 | write_id(&target, needid[target.keys[i].name].need); |
| 1948 | write_id(&target, needid[target.keys[i].type].need); |
| 1949 | if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET3) |
| 1950 | { |
| 1951 | if (target.keys[i].type == type_constantid) |
| 1952 | write_id(&target, needid[target.keys[i].size].need); |
| 1953 | else |
| 1954 | write_id(&target, target.keys[i].size); |
| 1955 | } |
| 1956 | else |
| 1957 | write_id(&target, cbdata.extdata[i].len); |
| 1958 | write_id(&target, target.keys[i].storage); |
| 1959 | } |
| 1960 | |
| 1961 | /* |
| 1962 | * write schemata |
| 1963 | */ |
| 1964 | write_id(&target, target.schemadatalen); /* XXX -1? */ |
| 1965 | for (i = 1; i < target.nschemata; i++) |
| 1966 | write_idarray(&target, pool, 0, repodata_id2schema(&target, i)); |
| 1967 | |
| 1968 | /********************************************************************/ |
| 1969 | |
| 1970 | write_id(&target, cbdata.maxdata); |
| 1971 | write_id(&target, cbdata.extdata[0].len); |
| 1972 | if (cbdata.extdata[0].len) |
| 1973 | write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len); |
| 1974 | solv_free(cbdata.extdata[0].buf); |
| 1975 | |
| 1976 | /* do we have vertical data? */ |
| 1977 | for (i = 1; i < target.nkeys; i++) |
| 1978 | if (cbdata.extdata[i].len) |
| 1979 | break; |
| 1980 | if (i < target.nkeys) |
| 1981 | { |
| 1982 | /* yes, write it in pages */ |
| 1983 | unsigned char vpage[REPOPAGE_BLOBSIZE(1 << 15)]; |
| 1984 | int lpage = 0; |
| 1985 | |
| 1986 | write_u32(&target, REPOPAGE_BLOBSIZE(1 << 15)); |
| 1987 | for (i = 1; i < target.nkeys; i++) |
| 1988 | if (cbdata.extdata[i].len) |
| 1989 | { |
| 1990 | if (cbdata.filelistmode) |
| 1991 | break; |
| 1992 | lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage); |
| 1993 | } |
| 1994 | if (cbdata.filelistmode && i < target.nkeys) |
| 1995 | { |
| 1996 | /* ok, just this single extdata, which is a filelist */ |
| 1997 | xd = cbdata.extdata + i; |
| 1998 | xd->len = 0; |
| 1999 | cbdata.filelistmode = -1; |
| 2000 | for (j = 0; j < cbdata.nkeymap; j++) |
| 2001 | if (cbdata.keymap[j] != i) |
| 2002 | cbdata.keymap[j] = 0; |
| 2003 | for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++) |
| 2004 | { |
| 2005 | if (s->repo != repo) |
| 2006 | continue; |
| 2007 | FOR_REPODATAS(repo, j, data)for (j = 1, data = repo->repodata + j; j < repo->nrepodata ; j++, data++) |
| 2008 | { |
| 2009 | if (!repodataused[j]) |
| 2010 | continue; |
| 2011 | if (i < data->start || i >= data->end) |
| 2012 | continue; |
| 2013 | repodata_search(data, i, 0, SEARCH_SUB(1<<9)|SEARCH_ARRAYSENTINEL(1<<10), repo_write_cb_adddata, &cbdata); |
| 2014 | } |
| 2015 | if (xd->len > 1024 * 1024) |
| 2016 | { |
| 2017 | lpage = write_compressed_extdata(&target, xd, vpage, lpage); |
| 2018 | xd->len = 0; |
| 2019 | } |
| 2020 | } |
| 2021 | if (xd->len) |
| 2022 | lpage = write_compressed_extdata(&target, xd, vpage, lpage); |
| 2023 | } |
| 2024 | if (lpage) |
| 2025 | write_compressed_page(&target, vpage, lpage); |
| 2026 | } |
| 2027 | |
| 2028 | for (i = 1; i < target.nkeys; i++) |
| 2029 | solv_free(cbdata.extdata[i].buf); |
| 2030 | solv_free(cbdata.extdata); |
| 2031 | |
| 2032 | target.fp = 0; |
| 2033 | repodata_freedata(&target); |
| 2034 | |
| 2035 | solv_free(needid); |
| 2036 | solv_free(cbdata.solvschemata); |
| 2037 | solv_free(cbdata.schema); |
| 2038 | |
| 2039 | solv_free(cbdata.keymap); |
| 2040 | solv_free(cbdata.keymapstart); |
| 2041 | solv_free(cbdata.dirused); |
| 2042 | solv_free(repodataused); |
| 2043 | return target.error; |
| 2044 | } |
| 2045 | |
| 2046 | struct repodata_write_data { |
| 2047 | int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata); |
| 2048 | void *kfdata; |
| 2049 | int repodataid; |
| 2050 | }; |
| 2051 | |
| 2052 | static int |
| 2053 | repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata) |
| 2054 | { |
| 2055 | struct repodata_write_data *wd = kfdata; |
| 2056 | |
| 2057 | /* XXX: special repodata selection hack */ |
| 2058 | if (key->name == 1 && key->size != wd->repodataid) |
| 2059 | return -1; |
| 2060 | if (key->storage == KEY_STORAGE_SOLVABLE1) |
| 2061 | return KEY_STORAGE_DROPPED0; /* not part of this repodata */ |
| 2062 | if (wd->keyfilter) |
| 2063 | return (*wd->keyfilter)(repo, key, wd->kfdata); |
| 2064 | return key->storage; |
| 2065 | } |
| 2066 | |
| 2067 | int |
| 2068 | repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq) |
| 2069 | { |
| 2070 | struct repodata_write_data wd; |
| 2071 | |
| 2072 | wd.keyfilter = keyfilter; |
| 2073 | wd.kfdata = kfdata; |
| 2074 | wd.repodataid = data->repodataid; |
| 2075 | return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq); |
| 2076 | } |
| 2077 | |
| 2078 | int |
| 2079 | repodata_write(Repodata *data, FILE *fp) |
| 2080 | { |
| 2081 | return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0); |
| 2082 | } |
| 2083 | |
| 2084 | int |
| 2085 | repo_write(Repo *repo, FILE *fp) |
| 2086 | { |
| 2087 | return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0); |
| 2088 | } |