2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
26 #include "poolid_private.h"
31 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
32 unsigned char *out, unsigned int out_len);
33 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
36 unsigned int out_len);
38 #define REPODATA_BLOCK 255
42 repodata_init(Repodata *data, Repo *repo, int localpool)
44 memset(data, 0, sizeof (*data));
46 data->localpool = localpool;
48 stringpool_init_empty(&data->spool);
49 data->keys = sat_calloc(1, sizeof(Repokey));
51 data->schemata = sat_calloc(1, sizeof(Id));
52 data->schemadata = sat_calloc(1, sizeof(Id));
54 data->schemadatalen = 1;
55 data->start = repo->start;
56 data->end = repo->end;
57 data->nextra = repo->nextra;
59 data->incoreoffset = sat_extend_resize(0, data->end - data->start, sizeof(Id), REPODATA_BLOCK);
60 data->extraoffset = sat_extend_resize(0, repo->nextra, sizeof(Id), REPODATA_BLOCK);
65 repodata_free(Repodata *data)
68 sat_free(data->schemata);
69 sat_free(data->schemadata);
71 sat_free(data->spool.strings);
72 sat_free(data->spool.stringspace);
73 sat_free(data->spool.stringhashtbl);
75 sat_free(data->dirpool.dirs);
76 sat_free(data->dirpool.dirtraverse);
78 sat_free(data->incoredata);
79 sat_free(data->incoreoffset);
80 sat_free(data->extraoffset);
81 sat_free(data->verticaloffset);
83 sat_free(data->blob_store);
84 sat_free(data->pages);
85 sat_free(data->mapped);
87 sat_free(data->vincore);
89 sat_free(data->attrs);
90 sat_free(data->extraattrs);
91 sat_free(data->attrdata);
92 sat_free(data->attriddata);
94 sat_free(data->location);
95 sat_free(data->addedfileprovides);
97 if (data->pagefd != -1)
101 static unsigned char *
102 forward_to_key(Repodata *data, Id keyid, Id schemaid, unsigned char *dp)
106 keyp = data->schemadata + data->schemata[schemaid];
107 while ((k = *keyp++) != 0)
111 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
113 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip that offset */
114 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip that length */
117 if (data->keys[k].storage != KEY_STORAGE_INCORE)
119 dp = data_skip(dp, data->keys[k].type);
124 #define BLOB_PAGEBITS 15
125 #define BLOB_PAGESIZE (1 << BLOB_PAGEBITS)
127 static unsigned char *
128 load_page_range(Repodata *data, unsigned int pstart, unsigned int pend)
130 /* Make sure all pages from PSTART to PEND (inclusive) are loaded,
131 and are consecutive. Return a pointer to the mapping of PSTART. */
132 unsigned char buf[BLOB_PAGESIZE];
135 /* Quick check in case all pages are there already and consecutive. */
136 for (i = pstart; i <= pend; i++)
137 if (data->pages[i].mapped_at == -1
139 && data->pages[i].mapped_at
140 != data->pages[i-1].mapped_at + BLOB_PAGESIZE))
143 return data->blob_store + data->pages[pstart].mapped_at;
145 if (data->pagefd == -1)
148 /* Ensure that we can map the numbers of pages we need at all. */
149 if (pend - pstart + 1 > data->ncanmap)
151 unsigned int oldcan = data->ncanmap;
152 data->ncanmap = pend - pstart + 1;
153 if (data->ncanmap < 4)
155 data->mapped = sat_realloc2(data->mapped, data->ncanmap, sizeof(data->mapped[0]));
156 memset (data->mapped + oldcan, 0, (data->ncanmap - oldcan) * sizeof (data->mapped[0]));
157 data->blob_store = sat_realloc2(data->blob_store, data->ncanmap, BLOB_PAGESIZE);
159 fprintf (stderr, "PAGE: can map %d pages\n", data->ncanmap);
163 /* Now search for "cheap" space in our store. Space is cheap if it's either
164 free (very cheap) or contains pages we search for anyway. */
166 /* Setup cost array. */
167 unsigned int cost[data->ncanmap];
168 for (i = 0; i < data->ncanmap; i++)
170 unsigned int pnum = data->mapped[i];
176 Attrblobpage *p = data->pages + pnum;
177 assert (p->mapped_at != -1);
178 if (pnum >= pstart && pnum <= pend)
185 /* And search for cheapest space. */
186 unsigned int best_cost = -1;
187 unsigned int best = 0;
188 unsigned int same_cost = 0;
189 for (i = 0; i + pend - pstart < data->ncanmap; i++)
191 unsigned int c = cost[i];
193 for (j = 0; j < pend - pstart + 1; j++)
196 best_cost = c, best = i;
197 else if (c == best_cost)
199 /* A null cost won't become better. */
203 /* If all places have the same cost we would thrash on slot 0. Avoid
204 this by doing a round-robin strategy in this case. */
205 if (same_cost == data->ncanmap - pend + pstart - 1)
206 best = data->rr_counter++ % (data->ncanmap - pend + pstart);
208 /* So we want to map our pages from [best] to [best+pend-pstart].
209 Use a very simple strategy, which doesn't make the best use of
210 our resources, but works. Throw away all pages in that range
211 (even ours) then copy around ours (in case they were outside the
212 range) or read them in. */
213 for (i = best; i < best + pend - pstart + 1; i++)
215 unsigned int pnum = data->mapped[i];
217 /* If this page is exactly at the right place already,
218 no need to evict it. */
219 && pnum != pstart + i - best)
221 /* Evict this page. */
223 fprintf (stderr, "PAGE: evict page %d from %d\n", pnum, i);
227 data->pages[pnum].mapped_at = -1;
231 /* Everything is free now. Read in the pages we want. */
232 for (i = pstart; i <= pend; i++)
234 Attrblobpage *p = data->pages + i;
235 unsigned int pnum = i - pstart + best;
236 void *dest = data->blob_store + pnum * BLOB_PAGESIZE;
237 if (p->mapped_at != -1)
239 if (p->mapped_at != pnum * BLOB_PAGESIZE)
242 fprintf (stderr, "PAGECOPY: %d to %d\n", i, pnum);
244 /* Still mapped somewhere else, so just copy it from there. */
245 memcpy (dest, data->blob_store + p->mapped_at, BLOB_PAGESIZE);
246 data->mapped[p->mapped_at / BLOB_PAGESIZE] = 0;
251 unsigned int in_len = p->file_size;
252 unsigned int compressed = in_len & 1;
255 fprintf (stderr, "PAGEIN: %d to %d", i, pnum);
257 if (pread(data->pagefd, compressed ? buf : dest, in_len, p->file_offset) != in_len)
259 perror ("mapping pread");
264 unsigned int out_len;
265 out_len = unchecked_decompress_buf(buf, in_len,
266 dest, BLOB_PAGESIZE);
267 if (out_len != BLOB_PAGESIZE && i < data->num_pages - 1)
269 fprintf(stderr, "can't decompress\n");
273 fprintf (stderr, " (expand %d to %d)", in_len, out_len);
277 fprintf (stderr, "\n");
280 p->mapped_at = pnum * BLOB_PAGESIZE;
281 data->mapped[pnum] = i + 1;
283 return data->blob_store + best * BLOB_PAGESIZE;
286 static unsigned char *
287 make_vertical_available(Repodata *data, Repokey *key, Id off, Id len)
292 if (off >= data->lastverticaloffset)
294 off -= data->lastverticaloffset;
295 if (off + len > data->vincorelen)
297 return data->vincore + off;
299 if (off + len > key->size)
301 /* we now have the offset, go into vertical */
302 off += data->verticaloffset[key - data->keys];
303 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
304 dp = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
306 dp += off % BLOB_PAGESIZE;
310 static inline unsigned char *
311 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
313 unsigned char *dp = *dpp;
317 if (key->storage == KEY_STORAGE_INCORE)
319 /* hmm, this is a bit expensive */
320 *dpp = data_skip(dp, key->type);
323 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
326 dp = data_read_id(dp, &off);
327 dp = data_read_id(dp, &len);
329 return make_vertical_available(data, key, off, len);
335 maybe_load_repodata(Repodata *data, Id *keyid)
337 if (data->state == REPODATA_STUB)
339 if (data->loadcallback)
343 /* key order may change when loading */
345 Id name = data->keys[*keyid].name;
346 Id type = data->keys[*keyid].type;
347 data->loadcallback(data);
348 if (data->state == REPODATA_AVAILABLE)
350 for (i = 1; i < data->nkeys; i++)
351 if (data->keys[i].name == name && data->keys[i].type == type)
360 data->loadcallback(data);
363 data->state = REPODATA_ERROR;
365 if (data->state == REPODATA_AVAILABLE)
367 data->state = REPODATA_ERROR;
371 static inline unsigned char*
372 entry2data(Repodata *data, Id entry)
375 return data->incoredata + data->extraoffset[-1 - entry];
377 return data->incoredata + data->incoreoffset[entry];
381 repodata_lookup_id(Repodata *data, Id entry, Id keyid)
388 if (!maybe_load_repodata(data, &keyid))
390 dp = entry2data(data, entry);
393 dp = data_read_id(dp, &schema);
394 /* make sure the schema of this solvable contains the key */
395 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
398 dp = forward_to_key(data, keyid, schema, dp);
399 key = data->keys + keyid;
400 dp = get_data(data, key, &dp);
403 if (key->type == REPOKEY_TYPE_CONSTANTID)
405 if (key->type != REPOKEY_TYPE_ID)
407 dp = data_read_id(dp, &id);
412 repodata_lookup_str(Repodata *data, Id entry, Id keyid)
419 if (!maybe_load_repodata(data, &keyid))
422 dp = entry2data(data, entry);
425 dp = data_read_id(dp, &schema);
426 /* make sure the schema of this solvable contains the key */
427 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
430 dp = forward_to_key(data, keyid, schema, dp);
431 key = data->keys + keyid;
432 dp = get_data(data, key, &dp);
435 if (key->type == REPOKEY_TYPE_STR)
436 return (const char *)dp;
437 if (key->type == REPOKEY_TYPE_CONSTANTID)
438 return id2str(data->repo->pool, key->size);
439 if (key->type == REPOKEY_TYPE_ID)
440 dp = data_read_id(dp, &id);
444 return data->spool.stringspace + data->spool.strings[id];
445 return id2str(data->repo->pool, id);
449 repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned int *value)
459 if (!maybe_load_repodata(data, &keyid))
462 dp = entry2data(data, entry);
465 dp = data_read_id(dp, &schema);
466 /* make sure the schema of this solvable contains the key */
467 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
470 dp = forward_to_key(data, keyid, schema, dp);
471 key = data->keys + keyid;
472 dp = get_data(data, key, &dp);
475 if (key->type == REPOKEY_TYPE_NUM
476 || key->type == REPOKEY_TYPE_U32
477 || key->type == REPOKEY_TYPE_CONSTANT)
479 dp = data_fetch(dp, &kv, key);
487 repodata_lookup_void(Repodata *data, Id entry, Id keyid)
492 if (!maybe_load_repodata(data, &keyid))
494 dp = entry2data(data, entry);
497 dp = data_read_id(dp, &schema);
498 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
504 const unsigned char *
505 repodata_lookup_bin_checksum(Repodata *data, Id entry, Id keyid, Id *typep)
512 if (!maybe_load_repodata(data, &keyid))
514 dp = entry2data(data, entry);
517 dp = data_read_id(dp, &schema);
518 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
521 dp = forward_to_key(data, keyid, schema, dp);
522 key = data->keys + keyid;
524 return get_data(data, key, &dp);
528 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
532 Id k, keyid, *kp, *keyp;
533 unsigned char *dp, *ddp;
539 || !maybe_load_repodata(data, 0))
542 dp = entry2data(data, entry);
545 dp = data_read_id(dp, &schema);
546 keyp = data->schemadata + data->schemata[schema];
549 /* search in a specific key */
550 for (kp = keyp; (k = *kp++) != 0; )
551 if (data->keys[k].name == keyname)
555 dp = forward_to_key(data, k, schema, dp);
561 while ((keyid = *keyp++) != 0)
564 key = data->keys + keyid;
565 ddp = get_data(data, key, &dp);
568 ddp = data_fetch(ddp, &kv, key);
571 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
573 while (!kv.eof && !stop);
574 if (onekey || stop > SEARCH_NEXT_KEY)
580 dataiterator_newdata(Dataiterator *di)
582 Id keyname = di->keyname;
583 Repodata *data = di->data;
586 if (data->state == REPODATA_STUB)
591 for (j = 1; j < data->nkeys; j++)
592 if (keyname == data->keys[j].name)
594 if (j == data->nkeys)
598 if (data->loadcallback)
599 data->loadcallback(data);
601 data->state = REPODATA_ERROR;
603 if (data->state == REPODATA_ERROR)
607 unsigned char *dp = data->incoredata;
611 dp += data->incoreoffset[di->solvid - data->start];
613 dp += data->extraoffset[-1 - di->solvid - data->extrastart];
614 dp = data_read_id(dp, &schema);
615 Id *keyp = data->schemadata + data->schemata[schema];
619 /* search in a specific key */
620 for (kp = keyp; (k = *kp++) != 0; )
621 if (data->keys[k].name == keyname)
625 dp = forward_to_key(data, k, schema, dp);
635 di->key = di->data->keys + keyid;
640 di->dp = get_data(di->data, di->key, &di->nextkeydp);
645 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
646 const char *match, int flags)
652 di->flags |= __SEARCH_ONESOLVABLE;
653 di->data = repo->repodata - 1;
654 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
661 di->solvid = repo->start - 1;
664 fprintf(stderr, "A repo contains the NULL solvable!\n");
667 di->data = repo->repodata + repo->nrepodata - 1;
671 di->keyname = keyname;
672 static Id zeroid = 0;
679 /* FIXME factor and merge with repo_matchvalue */
681 dataiterator_match(Dataiterator *di, KeyValue *kv)
683 int flags = di->flags;
685 if ((flags & SEARCH_STRINGMASK) != 0)
687 switch (di->key->type)
689 case REPOKEY_TYPE_ID:
690 case REPOKEY_TYPE_IDARRAY:
691 if (di->data && di->data->localpool)
692 kv->str = stringpool_id2str(&di->data->spool, kv->id);
694 kv->str = id2str(di->repo->pool, kv->id);
696 case REPOKEY_TYPE_STR:
701 switch ((flags & SEARCH_STRINGMASK))
703 case SEARCH_SUBSTRING:
704 if (flags & SEARCH_NOCASE)
706 if (!strcasestr(kv->str, di->match))
711 if (!strstr(kv->str, di->match))
716 if (flags & SEARCH_NOCASE)
718 if (strcasecmp(di->match, kv->str))
723 if (strcmp(di->match, kv->str))
728 if (fnmatch(di->match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
733 if (regexec(&di->regexp, kv->str, 0, NULL, 0))
743 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
744 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
745 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
746 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
747 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
748 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
749 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
750 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
751 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
752 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
753 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
754 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
755 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
756 { SOLVABLE_FRESHENS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
757 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
761 dataiterator_step(Dataiterator *di)
775 di->kv.eof = idp[1] ? 0 : 1;
781 Solvable *s = di->repo->pool->solvables + di->solvid;
782 int state = di->state;
783 di->key = solvablekeys + state - 1;
785 di->state = RPM_RPMDBID;
792 state = di->keyname - 1;
814 case SOLVABLE_VENDOR:
817 di->kv.id = s->vendor;
820 case SOLVABLE_PROVIDES:
821 di->idp = s->provides
822 ? di->repo->idarraydata + s->provides : 0;
824 case SOLVABLE_OBSOLETES:
825 di->idp = s->obsoletes
826 ? di->repo->idarraydata + s->obsoletes : 0;
828 case SOLVABLE_CONFLICTS:
829 di->idp = s->conflicts
830 ? di->repo->idarraydata + s->conflicts : 0;
832 case SOLVABLE_REQUIRES:
833 di->idp = s->requires
834 ? di->repo->idarraydata + s->requires : 0;
836 case SOLVABLE_RECOMMENDS:
837 di->idp = s->recommends
838 ? di->repo->idarraydata + s->recommends : 0;
840 case SOLVABLE_SUPPLEMENTS:
841 di->idp = s->supplements
842 ? di->repo->idarraydata + s->supplements : 0;
844 case SOLVABLE_SUGGESTS:
845 di->idp = s->suggests
846 ? di->repo->idarraydata + s->suggests : 0;
848 case SOLVABLE_ENHANCES:
849 di->idp = s->enhances
850 ? di->repo->idarraydata + s->enhances : 0;
852 case SOLVABLE_FRESHENS:
853 di->idp = s->freshens
854 ? di->repo->idarraydata + s->freshens : 0;
857 if (!di->repo->rpmdbid)
859 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
863 di->data = di->repo->repodata - 1;
874 di->dp = data_fetch(di->dp, &di->kv, di->key);
879 if (di->keyname || !(keyid = *di->keyp++))
883 Repo *repo = di->repo;
884 Repodata *data = ++di->data;
885 if (data >= repo->repodata + repo->nrepodata)
887 if (di->flags & __SEARCH_ONESOLVABLE)
891 while (++di->solvid < repo->end)
892 if (repo->pool->solvables[di->solvid].repo == repo)
894 if (di->solvid >= repo->end)
896 if (!(di->flags & SEARCH_EXTRA))
899 if (di->solvid < -repo->nextra)
906 if (di->solvid < -repo->nextra)
909 Pool *pool = di->repo->pool;
910 if (!(di->flags & SEARCH_ALL_REPOS)
911 || di->repo == pool->repos[pool->nrepos - 1])
914 for (i = 0; i < pool->nrepos; i++)
915 if (di->repo == pool->repos[i])
917 di->repo = pool->repos[i + 1];
918 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
922 di->data = repo->repodata - 1;
924 || (di->flags & SEARCH_NO_STORAGE_SOLVABLE))
926 static Id zeroid = 0;
931 if ((di->solvid < 0 && (-1 - di->solvid) >= data->extrastart && (-1 - di->solvid) < (data->extrastart + data->nextra))
932 || (di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
934 dataiterator_newdata(di);
942 di->key = di->data->keys + keyid;
943 di->dp = get_data(di->data, di->key, &di->nextkeydp);
945 di->dp = data_fetch(di->dp, &di->kv, di->key);
950 || dataiterator_match(di, &di->kv))
957 dataiterator_skip_attribute(Dataiterator *di)
961 /* This will make the next _step call to retrieve the next field. */
966 dataiterator_skip_solvable(Dataiterator *di)
968 /* We're done with this field. */
970 /* And with solvable data. */
972 /* And with all keys for this repodata and thing. */
973 static Id zeroid = 0;
975 /* And with all repodatas for this thing. */
976 di->data = di->repo->repodata + di->repo->nrepodata - 1;
977 /* Hence the next call to _step will retrieve the next thing. */
981 dataiterator_skip_repo(Dataiterator *di)
983 dataiterator_skip_solvable(di);
984 /* We're done with all solvables and all extra things for this repo. */
985 di->solvid = -1 - di->repo->nextra;
989 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
992 /* Simulate us being done with the solvable before the requested one. */
993 dataiterator_skip_solvable(di);
994 di->solvid = s - s->repo->pool->solvables;
999 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1002 dataiterator_skip_solvable(di);
1003 di->solvid = repo->start - 1;
1006 /* extend repodata so that it includes solvables p */
1008 repodata_extend(Repodata *data, Id p)
1010 if (data->start == data->end)
1011 data->start = data->end = p;
1014 int old = data->end - data->start;
1015 int new = p - data->end + 1;
1018 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1019 memset(data->attrs + old, 0, new * sizeof(Id *));
1021 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1022 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1025 if (p < data->start)
1027 int old = data->end - data->start;
1028 int new = data->start - p;
1031 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1032 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1033 memset(data->attrs, 0, new * sizeof(Id *));
1035 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1036 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1037 memset(data->incoreoffset, 0, new * sizeof(Id));
1043 repodata_extend_extra(Repodata *data, int nextra)
1045 if (nextra <= data->nextra)
1047 if (data->extraattrs)
1049 data->extraattrs = sat_extend(data->extraattrs, data->nextra, nextra - data->nextra, sizeof(Id *), REPODATA_BLOCK);
1050 memset(data->extraattrs + data->nextra, 0, (nextra - data->nextra) * sizeof (Id *));
1052 data->extraoffset = sat_extend(data->extraoffset, data->nextra, nextra - data->nextra, sizeof(Id), REPODATA_BLOCK);
1053 memset(data->extraoffset + data->nextra, 0, (nextra - data->nextra) * sizeof(Id));
1054 data->nextra = nextra;
1058 repodata_extend_block(Repodata *data, Id start, Id num)
1062 if (!data->incoreoffset)
1064 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1065 data->start = start;
1066 data->end = start + num;
1069 repodata_extend(data, start);
1071 repodata_extend(data, start + num - 1);
1074 /**********************************************************************/
1076 #define REPODATA_ATTRS_BLOCK 63
1077 #define REPODATA_ATTRDATA_BLOCK 1023
1078 #define REPODATA_ATTRIDDATA_BLOCK 63
1081 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
1086 if (!data->attrs && entry >= 0)
1088 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *),
1091 else if (!data->extraattrs && entry < 0)
1092 data->extraattrs = sat_calloc_block(data->nextra, sizeof(Id *), REPODATA_BLOCK);
1094 ap = data->extraattrs[-1 - entry];
1096 ap = data->attrs[entry];
1100 for (pp = ap; *pp; pp += 2)
1101 /* Determine equality based on the name only, allows us to change
1102 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1103 if (data->keys[*pp].name == data->keys[keyid].name)
1116 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1118 data->extraattrs[-1 - entry] = ap;
1120 data->attrs[entry] = ap;
1128 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
1132 /* find key in keys */
1133 for (keyid = 1; keyid < data->nkeys; keyid++)
1134 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
1136 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
1140 if (keyid == data->nkeys)
1142 /* allocate new key */
1143 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
1144 data->keys[data->nkeys++] = *key;
1145 if (data->verticaloffset)
1147 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
1148 data->verticaloffset[data->nkeys - 1] = 0;
1151 repodata_insert_keyid(data, entry, keyid, val, 1);
1155 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
1159 key.type = REPOKEY_TYPE_ID;
1161 key.storage = KEY_STORAGE_INCORE;
1162 repodata_set(data, entry, &key, id);
1166 repodata_set_num(Repodata *data, Id entry, Id keyname, unsigned int num)
1170 key.type = REPOKEY_TYPE_NUM;
1172 key.storage = KEY_STORAGE_INCORE;
1173 repodata_set(data, entry, &key, (Id)num);
1177 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
1181 if (data->localpool)
1182 id = stringpool_str2id(&data->spool, str, 1);
1184 id = str2id(data->repo->pool, str, 1);
1186 key.type = REPOKEY_TYPE_ID;
1188 key.storage = KEY_STORAGE_INCORE;
1189 repodata_set(data, entry, &key, id);
1193 repodata_set_constant(Repodata *data, Id entry, Id keyname, unsigned int constant)
1197 key.type = REPOKEY_TYPE_CONSTANT;
1198 key.size = constant;
1199 key.storage = KEY_STORAGE_INCORE;
1200 repodata_set(data, entry, &key, 0);
1204 repodata_set_constantid(Repodata *data, Id entry, Id keyname, Id id)
1208 key.type = REPOKEY_TYPE_CONSTANTID;
1210 key.storage = KEY_STORAGE_INCORE;
1211 repodata_set(data, entry, &key, 0);
1215 repodata_set_void(Repodata *data, Id entry, Id keyname)
1219 key.type = REPOKEY_TYPE_VOID;
1221 key.storage = KEY_STORAGE_INCORE;
1222 repodata_set(data, entry, &key, 0);
1226 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
1231 l = strlen(str) + 1;
1233 key.type = REPOKEY_TYPE_STR;
1235 key.storage = KEY_STORAGE_INCORE;
1236 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1237 memcpy(data->attrdata + data->attrdatalen, str, l);
1238 repodata_set(data, entry, &key, data->attrdatalen);
1239 data->attrdatalen += l;
1243 repoadata_add_array(Repodata *data, Id entry, Id keyname, Id keytype, int entrysize)
1249 pp = data->extraattrs ? data->extraattrs[-1 - entry] : 0;
1251 pp = data->attrs ? data->attrs[entry] : 0;
1253 for (; *pp; pp += 2)
1254 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1258 /* not found. allocate new key */
1263 key.storage = KEY_STORAGE_INCORE;
1264 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1265 repodata_set(data, entry, &key, data->attriddatalen);
1269 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1270 oldsize += entrysize;
1271 if (ida + 1 == data->attriddata + data->attriddatalen)
1273 /* this was the last entry, just append it */
1274 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1275 data->attriddatalen--; /* overwrite terminating 0 */
1279 /* too bad. move to back. */
1280 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1281 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1282 pp[1] = data->attriddatalen;
1283 data->attriddatalen += oldsize;
1288 checksumtype2len(Id type)
1292 case REPOKEY_TYPE_MD5:
1294 case REPOKEY_TYPE_SHA1:
1296 case REPOKEY_TYPE_SHA256:
1297 return SIZEOF_SHA256;
1304 repodata_set_bin_checksum(Repodata *data, Id entry, Id keyname, Id type,
1305 const unsigned char *str)
1308 int l = checksumtype2len(type);
1315 key.storage = KEY_STORAGE_INCORE;
1316 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1317 memcpy(data->attrdata + data->attrdatalen, str, l);
1318 repodata_set(data, entry, &key, data->attrdatalen);
1319 data->attrdatalen += l;
1323 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1326 for (i = 0; i < buflen; i++)
1328 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1329 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
1330 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
1341 buf[i] = (buf[i] << 4) | v;
1348 repodata_set_checksum(Repodata *data, Id entry, Id keyname, Id type,
1351 unsigned char buf[64];
1352 int l = checksumtype2len(type);
1356 if (hexstr2bytes(buf, str, l) != l)
1358 fprintf(stderr, "Invalid hex character in '%s'\n", str);
1361 repodata_set_bin_checksum(data, entry, keyname, type, buf);
1365 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1370 l = checksumtype2len(type);
1373 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1374 for (i = 0; i < l; i++)
1376 unsigned char v = buf[i];
1377 unsigned char w = v >> 4;
1378 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1380 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1387 repodata_globalize_id(Repodata *data, Id id)
1389 if (!data || !data->localpool)
1391 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
1395 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
1399 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
1401 repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1402 data->attriddata[data->attriddatalen++] = dir;
1403 data->attriddata[data->attriddatalen++] = num;
1404 data->attriddata[data->attriddatalen++] = num2;
1405 data->attriddata[data->attriddatalen++] = 0;
1409 repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
1414 l = strlen(str) + 1;
1415 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1416 memcpy(data->attrdata + data->attrdatalen, str, l);
1417 stroff = data->attrdatalen;
1418 data->attrdatalen += l;
1421 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", entry, dir, str, data->attriddatalen);
1423 repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1424 data->attriddata[data->attriddatalen++] = dir;
1425 data->attriddata[data->attriddatalen++] = stroff;
1426 data->attriddata[data->attriddatalen++] = 0;
1430 repodata_add_idarray(Repodata *data, Id entry, Id keyname, Id id)
1433 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", entry, id, data->attriddatalen);
1435 repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_IDARRAY, 1);
1436 data->attriddata[data->attriddatalen++] = id;
1437 data->attriddata[data->attriddatalen++] = 0;
1441 repodata_add_poolstr_array(Repodata *data, Id entry, Id keyname,
1445 if (data->localpool)
1446 id = stringpool_str2id(&data->spool, str, 1);
1448 id = str2id(data->repo->pool, str, 1);
1449 repodata_add_idarray(data, entry, keyname, id);
1453 repodata_merge_attrs(Repodata *data, Id dest, Id src)
1457 || !(keyp = src < 0 ? data->extraattrs[-1 - src] : data->attrs[src]))
1459 for (; *keyp; keyp += 2)
1460 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
1463 /*********************************/
1465 /* unify with repo_write! */
1467 #define EXTDATA_BLOCK 1023
1468 #define SCHEMATA_BLOCK 31
1469 #define SCHEMATADATA_BLOCK 255
1477 data_addid(struct extdata *xd, Id x)
1480 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
1481 dp = xd->buf + xd->len;
1486 *dp++ = (x >> 28) | 128;
1488 *dp++ = (x >> 21) | 128;
1489 *dp++ = (x >> 14) | 128;
1492 *dp++ = (x >> 7) | 128;
1494 xd->len = dp - xd->buf;
1498 data_addideof(struct extdata *xd, Id x, int eof)
1501 x = (x & 63) | ((x & ~63) << 1);
1502 data_addid(xd, (eof ? x: x | 64));
1506 data_addblob(struct extdata *xd, unsigned char *blob, int len)
1508 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
1509 memcpy(xd->buf + xd->len, blob, len);
1513 /*********************************/
1516 addschema_prepare(Repodata *data, Id *schematacache)
1521 memset(schematacache, 0, 256 * sizeof(Id));
1522 for (i = 0; i < data->nschemata; i++)
1524 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
1527 schematacache[h] = i + 1;
1529 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
1530 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
1534 addschema(Repodata *data, Id *schema, Id *schematacache)
1539 for (sp = schema, len = 0, h = 0; *sp; len++)
1544 cid = schematacache[h];
1548 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
1550 /* cache conflict */
1551 for (cid = 0; cid < data->nschemata; cid++)
1552 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
1555 /* a new one. make room. */
1556 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
1557 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
1559 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
1560 data->schemata[data->nschemata] = data->schemadatalen;
1561 data->schemadatalen += len;
1562 schematacache[h] = data->nschemata + 1;
1564 fprintf(stderr, "addschema: new schema\n");
1566 return data->nschemata++;
1571 repodata_internalize(Repodata *data)
1574 Id id, entry, nentry, *ida;
1575 Id schematacache[256];
1576 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
1577 unsigned char *dp, *ndp;
1578 int newschema, oldcount;
1579 struct extdata newincore;
1580 struct extdata newvincore;
1582 if (!data->attrs && !data->extraattrs)
1585 newvincore.buf = data->vincore;
1586 newvincore.len = data->vincorelen;
1588 schema = sat_malloc2(data->nkeys, sizeof(Id));
1589 seen = sat_malloc2(data->nkeys, sizeof(Id));
1591 /* Merge the data already existing (in data->schemata, ->incoredata and
1592 friends) with the new attributes in data->attrs[]. */
1593 nentry = data->end - data->start;
1594 addschema_prepare(data, schematacache);
1595 memset(&newincore, 0, sizeof(newincore));
1596 data_addid(&newincore, 0);
1599 for (entry = data->extraattrs ? -data->nextra : 0; entry < nentry; entry++)
1601 memset(seen, 0, data->nkeys * sizeof(Id));
1603 dp = entry2data(data, entry);
1604 if (data->incoredata)
1605 dp = data_read_id(dp, &oldschema);
1609 fprintf(stderr, "oldschema %d\n", oldschema);
1610 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
1611 fprintf(stderr, "schemadata %p\n", data->schemadata);
1613 /* seen: -1: old data 0: skipped >0: id + 1 */
1616 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
1620 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
1627 keyp = entry < 0 ? data->extraattrs[-1 - entry] : data->attrs[entry];
1629 for (; *keyp; keyp += 2)
1636 seen[*keyp] = keyp[1] + 1;
1640 /* Ideally we'd like to sort the new schema here, to ensure
1641 schema equality independend of the ordering. We can't do that
1642 yet. For once see below (old ids need to come before new ids).
1643 An additional difficulty is that we also need to move
1644 the values with the keys. */
1645 schemaid = addschema(data, schema, schematacache);
1647 schemaid = oldschema;
1650 /* Now create data blob. We walk through the (possibly new) schema
1651 and either copy over old data, or insert the new. */
1652 /* XXX Here we rely on the fact that the (new) schema has the form
1653 o1 o2 o3 o4 ... | n1 n2 n3 ...
1654 (oX being the old keyids (possibly overwritten), and nX being
1655 the new keyids). This rules out sorting the keyids in order
1656 to ensure a small schema count. */
1658 data->extraoffset[-1 - entry] = newincore.len;
1660 data->incoreoffset[entry] = newincore.len;
1661 data_addid(&newincore, schemaid);
1662 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
1664 key = data->keys + *keyp;
1668 /* Skip the data associated with this old key. */
1669 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1671 ndp = data_skip(dp, REPOKEY_TYPE_ID);
1672 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
1674 else if (key->storage == KEY_STORAGE_INCORE)
1675 ndp = data_skip(dp, key->type);
1678 if (seen[*keyp] == -1)
1680 /* If this key was an old one _and_ was not overwritten with
1681 a different value copy over the old value (we skipped it
1684 data_addblob(&newincore, dp, ndp - dp);
1687 else if (seen[*keyp])
1689 /* Otherwise we have a new value. Parse it into the internal
1692 unsigned int oldvincorelen = 0;
1695 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1698 oldvincorelen = xd->len;
1700 id = seen[*keyp] - 1;
1703 case REPOKEY_TYPE_VOID:
1704 case REPOKEY_TYPE_CONSTANT:
1705 case REPOKEY_TYPE_CONSTANTID:
1707 case REPOKEY_TYPE_STR:
1708 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1710 case REPOKEY_TYPE_MD5:
1711 data_addblob(xd, data->attrdata + id, SIZEOF_MD5);
1713 case REPOKEY_TYPE_SHA1:
1714 data_addblob(xd, data->attrdata + id, SIZEOF_SHA1);
1716 case REPOKEY_TYPE_ID:
1717 case REPOKEY_TYPE_NUM:
1718 case REPOKEY_TYPE_DIR:
1721 case REPOKEY_TYPE_IDARRAY:
1722 for (ida = data->attriddata + id; *ida; ida++)
1723 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
1725 case REPOKEY_TYPE_DIRNUMNUMARRAY:
1726 for (ida = data->attriddata + id; *ida; ida += 3)
1728 data_addid(xd, ida[0]);
1729 data_addid(xd, ida[1]);
1730 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1733 case REPOKEY_TYPE_DIRSTRARRAY:
1734 for (ida = data->attriddata + id; *ida; ida += 2)
1736 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1737 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1741 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1744 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1746 /* put offset/len in incore */
1747 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1748 oldvincorelen = xd->len - oldvincorelen;
1749 data_addid(&newincore, oldvincorelen);
1754 if (entry < 0 && data->extraattrs[-1 - entry])
1755 sat_free(data->extraattrs[-1 - entry]);
1756 else if (entry >= 0 && data->attrs[entry])
1757 sat_free(data->attrs[entry]);
1762 sat_free(data->incoredata);
1763 data->incoredata = newincore.buf;
1764 data->incoredatalen = newincore.len;
1765 data->incoredatafree = 0;
1767 sat_free(data->vincore);
1768 data->vincore = newvincore.buf;
1769 data->vincorelen = newvincore.len;
1771 data->attrs = sat_free(data->attrs);
1772 data->extraattrs = sat_free(data->extraattrs);
1773 data->attrdata = sat_free(data->attrdata);
1774 data->attriddata = sat_free(data->attriddata);
1775 data->attrdatalen = 0;
1776 data->attriddatalen = 0;
1780 repodata_str2dir(Repodata *data, const char *dir, int create)
1786 while (*dir == '/' && dir[1] == '/')
1788 if (*dir == '/' && !dir[1])
1792 dire = strchrnul(dir, '/');
1793 if (data->localpool)
1794 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1796 id = strn2id(data->repo->pool, dir, dire - dir, create);
1799 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1812 repodata_dir2str(Repodata *data, Id did, const char *suf)
1814 Pool *pool = data->repo->pool;
1821 return suf ? suf : "";
1825 comp = dirpool_compid(&data->dirpool, parent);
1826 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
1828 parent = dirpool_parent(&data->dirpool, parent);
1833 l += strlen(suf) + 1;
1834 p = pool_alloctmpspace(pool, l + 1) + l;
1845 comp = dirpool_compid(&data->dirpool, parent);
1846 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
1849 strncpy(p, comps, l);
1850 parent = dirpool_parent(&data->dirpool, parent);
1858 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1860 return compress_buf(page, len, cpage, max);
1863 #define SOLV_ERROR_EOF 3
1865 static inline unsigned int
1871 for (i = 0; i < 4; i++)
1881 #define SOLV_ERROR_EOF 3
1882 #define SOLV_ERROR_CORRUPT 6
1884 /* Try to either setup on-demand paging (using FP as backing
1885 file), or in case that doesn't work (FP not seekable) slurps in
1886 all pages and deactivates paging. */
1888 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1890 FILE *fp = data->fp;
1891 unsigned int npages;
1893 unsigned int can_seek;
1895 unsigned char buf[BLOB_PAGESIZE];
1897 if (pagesz != BLOB_PAGESIZE)
1899 /* We could handle this by slurping in everything. */
1900 data->error = SOLV_ERROR_CORRUPT;
1904 if ((cur_file_ofs = ftell(fp)) < 0)
1908 data->pagefd = dup(fileno(fp));
1909 if (data->pagefd == -1)
1913 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1915 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1917 data->num_pages = npages;
1918 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1920 /* If we can't seek on our input we have to slurp in everything. */
1922 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1923 for (i = 0; i < npages; i++)
1925 unsigned int in_len = read_u32(fp);
1926 unsigned int compressed = in_len & 1;
1927 Attrblobpage *p = data->pages + i;
1930 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1931 i, in_len, compressed ? "" : "not ");
1937 p->file_offset = cur_file_ofs;
1938 p->file_size = in_len * 2 + compressed;
1939 if (fseek(fp, in_len, SEEK_CUR) < 0)
1942 fprintf (stderr, "can't seek after we thought we can\n");
1943 /* We can't fall back to non-seeking behaviour as we already
1944 read over some data pages without storing them away. */
1945 data->error = SOLV_ERROR_EOF;
1946 close(data->pagefd);
1950 cur_file_ofs += in_len;
1954 unsigned int out_len;
1955 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1956 p->mapped_at = i * BLOB_PAGESIZE;
1959 /* We can't seek, so suck everything in. */
1960 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1963 data->error = SOLV_ERROR_EOF;
1968 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1969 if (out_len != BLOB_PAGESIZE && i < npages - 1)
1971 data->error = SOLV_ERROR_CORRUPT;
1980 repodata_disable_paging(Repodata *data)
1982 if (maybe_load_repodata(data, 0)
1984 load_page_range (data, 0, data->num_pages - 1);
1987 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: