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;
672 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
676 /* We feed multiple lines eventually (e.g. authors or descriptions),
677 so set REG_NEWLINE. */
679 regcomp(&di->regex, di->match,
680 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
681 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
683 if (di->regex_err != 0)
685 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
686 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
693 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
699 di->keyname = keyname;
700 static Id zeroid = 0;
707 /* FIXME factor and merge with repo_matchvalue */
709 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
711 KeyValue *kv = &di->kv;
712 const char *match = vmatch;
713 if ((flags & SEARCH_STRINGMASK) != 0)
715 switch (di->key->type)
717 case REPOKEY_TYPE_ID:
718 case REPOKEY_TYPE_IDARRAY:
719 if (di->data && di->data->localpool)
720 kv->str = stringpool_id2str(&di->data->spool, kv->id);
722 kv->str = id2str(di->repo->pool, kv->id);
724 case REPOKEY_TYPE_STR:
729 switch ((flags & SEARCH_STRINGMASK))
731 case SEARCH_SUBSTRING:
732 if (flags & SEARCH_NOCASE)
734 if (!strcasestr(kv->str, match))
739 if (!strstr(kv->str, match))
744 if (flags & SEARCH_NOCASE)
746 if (strcasecmp(match, kv->str))
751 if (strcmp(match, kv->str))
756 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
760 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
771 dataiterator_match_int(Dataiterator *di)
773 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
774 return dataiterator_match_int_real(di, di->flags, &di->regex);
776 return dataiterator_match_int_real(di, di->flags, di->match);
780 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
782 return dataiterator_match_int_real(di, flags, vmatch);
785 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
786 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
787 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
788 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
789 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
790 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
791 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
792 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
793 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
794 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
795 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
796 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
797 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
798 { SOLVABLE_FRESHENS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
799 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
803 dataiterator_step(Dataiterator *di)
817 di->kv.eof = idp[1] ? 0 : 1;
823 Solvable *s = di->repo->pool->solvables + di->solvid;
824 int state = di->state;
825 di->key = solvablekeys + state - 1;
827 di->state = RPM_RPMDBID;
834 state = di->keyname - 1;
856 case SOLVABLE_VENDOR:
859 di->kv.id = s->vendor;
862 case SOLVABLE_PROVIDES:
863 di->idp = s->provides
864 ? di->repo->idarraydata + s->provides : 0;
866 case SOLVABLE_OBSOLETES:
867 di->idp = s->obsoletes
868 ? di->repo->idarraydata + s->obsoletes : 0;
870 case SOLVABLE_CONFLICTS:
871 di->idp = s->conflicts
872 ? di->repo->idarraydata + s->conflicts : 0;
874 case SOLVABLE_REQUIRES:
875 di->idp = s->requires
876 ? di->repo->idarraydata + s->requires : 0;
878 case SOLVABLE_RECOMMENDS:
879 di->idp = s->recommends
880 ? di->repo->idarraydata + s->recommends : 0;
882 case SOLVABLE_SUPPLEMENTS:
883 di->idp = s->supplements
884 ? di->repo->idarraydata + s->supplements : 0;
886 case SOLVABLE_SUGGESTS:
887 di->idp = s->suggests
888 ? di->repo->idarraydata + s->suggests : 0;
890 case SOLVABLE_ENHANCES:
891 di->idp = s->enhances
892 ? di->repo->idarraydata + s->enhances : 0;
894 case SOLVABLE_FRESHENS:
895 di->idp = s->freshens
896 ? di->repo->idarraydata + s->freshens : 0;
899 if (!di->repo->rpmdbid)
901 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
905 di->data = di->repo->repodata - 1;
916 di->dp = data_fetch(di->dp, &di->kv, di->key);
921 if (di->keyname || !(keyid = *di->keyp++))
925 Repo *repo = di->repo;
926 Repodata *data = ++di->data;
927 if (data >= repo->repodata + repo->nrepodata)
929 if (di->flags & __SEARCH_ONESOLVABLE)
933 while (++di->solvid < repo->end)
934 if (repo->pool->solvables[di->solvid].repo == repo)
936 if (di->solvid >= repo->end)
938 if (!(di->flags & SEARCH_EXTRA))
941 if (di->solvid < -repo->nextra)
948 if (di->solvid < -repo->nextra)
951 Pool *pool = di->repo->pool;
952 if (!(di->flags & SEARCH_ALL_REPOS)
953 || di->repo == pool->repos[pool->nrepos - 1])
956 for (i = 0; i < pool->nrepos; i++)
957 if (di->repo == pool->repos[i])
959 di->repo = pool->repos[i + 1];
960 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
964 di->data = repo->repodata - 1;
966 || (di->flags & SEARCH_NO_STORAGE_SOLVABLE))
968 static Id zeroid = 0;
973 if ((di->solvid < 0 && (-1 - di->solvid) >= data->extrastart && (-1 - di->solvid) < (data->extrastart + data->nextra))
974 || (di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
976 dataiterator_newdata(di);
984 di->key = di->data->keys + keyid;
985 di->dp = get_data(di->data, di->key, &di->nextkeydp);
987 di->dp = data_fetch(di->dp, &di->kv, di->key);
992 || dataiterator_match_int(di))
999 dataiterator_skip_attribute(Dataiterator *di)
1003 /* This will make the next _step call to retrieve the next field. */
1008 dataiterator_skip_solvable(Dataiterator *di)
1010 /* We're done with this field. */
1012 /* And with solvable data. */
1014 /* And with all keys for this repodata and thing. */
1015 static Id zeroid = 0;
1017 /* And with all repodatas for this thing. */
1018 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1019 /* Hence the next call to _step will retrieve the next thing. */
1023 dataiterator_skip_repo(Dataiterator *di)
1025 dataiterator_skip_solvable(di);
1026 /* We're done with all solvables and all extra things for this repo. */
1027 di->solvid = -1 - di->repo->nextra;
1031 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1034 /* Simulate us being done with the solvable before the requested one. */
1035 dataiterator_skip_solvable(di);
1036 di->solvid = s - s->repo->pool->solvables;
1041 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1044 dataiterator_skip_solvable(di);
1045 di->solvid = repo->start - 1;
1048 /* extend repodata so that it includes solvables p */
1050 repodata_extend(Repodata *data, Id p)
1052 if (data->start == data->end)
1053 data->start = data->end = p;
1056 int old = data->end - data->start;
1057 int new = p - data->end + 1;
1060 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1061 memset(data->attrs + old, 0, new * sizeof(Id *));
1063 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1064 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1067 if (p < data->start)
1069 int old = data->end - data->start;
1070 int new = data->start - p;
1073 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1074 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1075 memset(data->attrs, 0, new * sizeof(Id *));
1077 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1078 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1079 memset(data->incoreoffset, 0, new * sizeof(Id));
1085 repodata_extend_extra(Repodata *data, int nextra)
1087 if (nextra <= data->nextra)
1089 if (data->extraattrs)
1091 data->extraattrs = sat_extend(data->extraattrs, data->nextra, nextra - data->nextra, sizeof(Id *), REPODATA_BLOCK);
1092 memset(data->extraattrs + data->nextra, 0, (nextra - data->nextra) * sizeof (Id *));
1094 data->extraoffset = sat_extend(data->extraoffset, data->nextra, nextra - data->nextra, sizeof(Id), REPODATA_BLOCK);
1095 memset(data->extraoffset + data->nextra, 0, (nextra - data->nextra) * sizeof(Id));
1096 data->nextra = nextra;
1100 repodata_extend_block(Repodata *data, Id start, Id num)
1104 if (!data->incoreoffset)
1106 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1107 data->start = start;
1108 data->end = start + num;
1111 repodata_extend(data, start);
1113 repodata_extend(data, start + num - 1);
1116 /**********************************************************************/
1118 #define REPODATA_ATTRS_BLOCK 63
1119 #define REPODATA_ATTRDATA_BLOCK 1023
1120 #define REPODATA_ATTRIDDATA_BLOCK 63
1123 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
1128 if (!data->attrs && entry >= 0)
1130 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *),
1133 else if (!data->extraattrs && entry < 0)
1134 data->extraattrs = sat_calloc_block(data->nextra, sizeof(Id *), REPODATA_BLOCK);
1136 ap = data->extraattrs[-1 - entry];
1138 ap = data->attrs[entry];
1142 for (pp = ap; *pp; pp += 2)
1143 /* Determine equality based on the name only, allows us to change
1144 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1145 if (data->keys[*pp].name == data->keys[keyid].name)
1158 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1160 data->extraattrs[-1 - entry] = ap;
1162 data->attrs[entry] = ap;
1170 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
1174 /* find key in keys */
1175 for (keyid = 1; keyid < data->nkeys; keyid++)
1176 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
1178 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
1182 if (keyid == data->nkeys)
1184 /* allocate new key */
1185 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
1186 data->keys[data->nkeys++] = *key;
1187 if (data->verticaloffset)
1189 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
1190 data->verticaloffset[data->nkeys - 1] = 0;
1193 repodata_insert_keyid(data, entry, keyid, val, 1);
1197 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
1201 key.type = REPOKEY_TYPE_ID;
1203 key.storage = KEY_STORAGE_INCORE;
1204 repodata_set(data, entry, &key, id);
1208 repodata_set_num(Repodata *data, Id entry, Id keyname, unsigned int num)
1212 key.type = REPOKEY_TYPE_NUM;
1214 key.storage = KEY_STORAGE_INCORE;
1215 repodata_set(data, entry, &key, (Id)num);
1219 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
1223 if (data->localpool)
1224 id = stringpool_str2id(&data->spool, str, 1);
1226 id = str2id(data->repo->pool, str, 1);
1228 key.type = REPOKEY_TYPE_ID;
1230 key.storage = KEY_STORAGE_INCORE;
1231 repodata_set(data, entry, &key, id);
1235 repodata_set_constant(Repodata *data, Id entry, Id keyname, unsigned int constant)
1239 key.type = REPOKEY_TYPE_CONSTANT;
1240 key.size = constant;
1241 key.storage = KEY_STORAGE_INCORE;
1242 repodata_set(data, entry, &key, 0);
1246 repodata_set_constantid(Repodata *data, Id entry, Id keyname, Id id)
1250 key.type = REPOKEY_TYPE_CONSTANTID;
1252 key.storage = KEY_STORAGE_INCORE;
1253 repodata_set(data, entry, &key, 0);
1257 repodata_set_void(Repodata *data, Id entry, Id keyname)
1261 key.type = REPOKEY_TYPE_VOID;
1263 key.storage = KEY_STORAGE_INCORE;
1264 repodata_set(data, entry, &key, 0);
1268 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
1273 l = strlen(str) + 1;
1275 key.type = REPOKEY_TYPE_STR;
1277 key.storage = KEY_STORAGE_INCORE;
1278 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1279 memcpy(data->attrdata + data->attrdatalen, str, l);
1280 repodata_set(data, entry, &key, data->attrdatalen);
1281 data->attrdatalen += l;
1285 repoadata_add_array(Repodata *data, Id entry, Id keyname, Id keytype, int entrysize)
1291 pp = data->extraattrs ? data->extraattrs[-1 - entry] : 0;
1293 pp = data->attrs ? data->attrs[entry] : 0;
1295 for (; *pp; pp += 2)
1296 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1300 /* not found. allocate new key */
1305 key.storage = KEY_STORAGE_INCORE;
1306 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1307 repodata_set(data, entry, &key, data->attriddatalen);
1311 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1312 oldsize += entrysize;
1313 if (ida + 1 == data->attriddata + data->attriddatalen)
1315 /* this was the last entry, just append it */
1316 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1317 data->attriddatalen--; /* overwrite terminating 0 */
1321 /* too bad. move to back. */
1322 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1323 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1324 pp[1] = data->attriddatalen;
1325 data->attriddatalen += oldsize;
1330 checksumtype2len(Id type)
1334 case REPOKEY_TYPE_MD5:
1336 case REPOKEY_TYPE_SHA1:
1338 case REPOKEY_TYPE_SHA256:
1339 return SIZEOF_SHA256;
1346 repodata_set_bin_checksum(Repodata *data, Id entry, Id keyname, Id type,
1347 const unsigned char *str)
1350 int l = checksumtype2len(type);
1357 key.storage = KEY_STORAGE_INCORE;
1358 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1359 memcpy(data->attrdata + data->attrdatalen, str, l);
1360 repodata_set(data, entry, &key, data->attrdatalen);
1361 data->attrdatalen += l;
1365 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1368 for (i = 0; i < buflen; i++)
1370 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1371 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
1372 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
1383 buf[i] = (buf[i] << 4) | v;
1390 repodata_set_checksum(Repodata *data, Id entry, Id keyname, Id type,
1393 unsigned char buf[64];
1394 int l = checksumtype2len(type);
1398 if (hexstr2bytes(buf, str, l) != l)
1400 fprintf(stderr, "Invalid hex character in '%s'\n", str);
1403 repodata_set_bin_checksum(data, entry, keyname, type, buf);
1407 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1412 l = checksumtype2len(type);
1415 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1416 for (i = 0; i < l; i++)
1418 unsigned char v = buf[i];
1419 unsigned char w = v >> 4;
1420 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1422 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1429 repodata_globalize_id(Repodata *data, Id id)
1431 if (!data || !data->localpool)
1433 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
1437 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
1441 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
1443 repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1444 data->attriddata[data->attriddatalen++] = dir;
1445 data->attriddata[data->attriddatalen++] = num;
1446 data->attriddata[data->attriddatalen++] = num2;
1447 data->attriddata[data->attriddatalen++] = 0;
1451 repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
1456 l = strlen(str) + 1;
1457 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1458 memcpy(data->attrdata + data->attrdatalen, str, l);
1459 stroff = data->attrdatalen;
1460 data->attrdatalen += l;
1463 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", entry, dir, str, data->attriddatalen);
1465 repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1466 data->attriddata[data->attriddatalen++] = dir;
1467 data->attriddata[data->attriddatalen++] = stroff;
1468 data->attriddata[data->attriddatalen++] = 0;
1472 repodata_add_idarray(Repodata *data, Id entry, Id keyname, Id id)
1475 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", entry, id, data->attriddatalen);
1477 repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_IDARRAY, 1);
1478 data->attriddata[data->attriddatalen++] = id;
1479 data->attriddata[data->attriddatalen++] = 0;
1483 repodata_add_poolstr_array(Repodata *data, Id entry, Id keyname,
1487 if (data->localpool)
1488 id = stringpool_str2id(&data->spool, str, 1);
1490 id = str2id(data->repo->pool, str, 1);
1491 repodata_add_idarray(data, entry, keyname, id);
1495 repodata_merge_attrs(Repodata *data, Id dest, Id src)
1499 || !(keyp = src < 0 ? data->extraattrs[-1 - src] : data->attrs[src]))
1501 for (; *keyp; keyp += 2)
1502 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
1505 /*********************************/
1507 /* unify with repo_write! */
1509 #define EXTDATA_BLOCK 1023
1510 #define SCHEMATA_BLOCK 31
1511 #define SCHEMATADATA_BLOCK 255
1519 data_addid(struct extdata *xd, Id x)
1522 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
1523 dp = xd->buf + xd->len;
1528 *dp++ = (x >> 28) | 128;
1530 *dp++ = (x >> 21) | 128;
1531 *dp++ = (x >> 14) | 128;
1534 *dp++ = (x >> 7) | 128;
1536 xd->len = dp - xd->buf;
1540 data_addideof(struct extdata *xd, Id x, int eof)
1543 x = (x & 63) | ((x & ~63) << 1);
1544 data_addid(xd, (eof ? x: x | 64));
1548 data_addblob(struct extdata *xd, unsigned char *blob, int len)
1550 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
1551 memcpy(xd->buf + xd->len, blob, len);
1555 /*********************************/
1558 addschema_prepare(Repodata *data, Id *schematacache)
1563 memset(schematacache, 0, 256 * sizeof(Id));
1564 for (i = 0; i < data->nschemata; i++)
1566 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
1569 schematacache[h] = i + 1;
1571 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
1572 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
1576 addschema(Repodata *data, Id *schema, Id *schematacache)
1581 for (sp = schema, len = 0, h = 0; *sp; len++)
1586 cid = schematacache[h];
1590 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
1592 /* cache conflict */
1593 for (cid = 0; cid < data->nschemata; cid++)
1594 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
1597 /* a new one. make room. */
1598 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
1599 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
1601 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
1602 data->schemata[data->nschemata] = data->schemadatalen;
1603 data->schemadatalen += len;
1604 schematacache[h] = data->nschemata + 1;
1606 fprintf(stderr, "addschema: new schema\n");
1608 return data->nschemata++;
1613 repodata_internalize(Repodata *data)
1616 Id id, entry, nentry, *ida;
1617 Id schematacache[256];
1618 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
1619 unsigned char *dp, *ndp;
1620 int newschema, oldcount;
1621 struct extdata newincore;
1622 struct extdata newvincore;
1624 if (!data->attrs && !data->extraattrs)
1627 newvincore.buf = data->vincore;
1628 newvincore.len = data->vincorelen;
1630 schema = sat_malloc2(data->nkeys, sizeof(Id));
1631 seen = sat_malloc2(data->nkeys, sizeof(Id));
1633 /* Merge the data already existing (in data->schemata, ->incoredata and
1634 friends) with the new attributes in data->attrs[]. */
1635 nentry = data->end - data->start;
1636 addschema_prepare(data, schematacache);
1637 memset(&newincore, 0, sizeof(newincore));
1638 data_addid(&newincore, 0);
1641 for (entry = data->extraattrs ? -data->nextra : 0; entry < nentry; entry++)
1643 memset(seen, 0, data->nkeys * sizeof(Id));
1645 dp = entry2data(data, entry);
1646 if (data->incoredata)
1647 dp = data_read_id(dp, &oldschema);
1651 fprintf(stderr, "oldschema %d\n", oldschema);
1652 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
1653 fprintf(stderr, "schemadata %p\n", data->schemadata);
1655 /* seen: -1: old data 0: skipped >0: id + 1 */
1658 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
1662 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
1669 keyp = entry < 0 ? data->extraattrs[-1 - entry] : data->attrs[entry];
1671 for (; *keyp; keyp += 2)
1678 seen[*keyp] = keyp[1] + 1;
1682 /* Ideally we'd like to sort the new schema here, to ensure
1683 schema equality independend of the ordering. We can't do that
1684 yet. For once see below (old ids need to come before new ids).
1685 An additional difficulty is that we also need to move
1686 the values with the keys. */
1687 schemaid = addschema(data, schema, schematacache);
1689 schemaid = oldschema;
1692 /* Now create data blob. We walk through the (possibly new) schema
1693 and either copy over old data, or insert the new. */
1694 /* XXX Here we rely on the fact that the (new) schema has the form
1695 o1 o2 o3 o4 ... | n1 n2 n3 ...
1696 (oX being the old keyids (possibly overwritten), and nX being
1697 the new keyids). This rules out sorting the keyids in order
1698 to ensure a small schema count. */
1700 data->extraoffset[-1 - entry] = newincore.len;
1702 data->incoreoffset[entry] = newincore.len;
1703 data_addid(&newincore, schemaid);
1704 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
1706 key = data->keys + *keyp;
1710 /* Skip the data associated with this old key. */
1711 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1713 ndp = data_skip(dp, REPOKEY_TYPE_ID);
1714 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
1716 else if (key->storage == KEY_STORAGE_INCORE)
1717 ndp = data_skip(dp, key->type);
1720 if (seen[*keyp] == -1)
1722 /* If this key was an old one _and_ was not overwritten with
1723 a different value copy over the old value (we skipped it
1726 data_addblob(&newincore, dp, ndp - dp);
1729 else if (seen[*keyp])
1731 /* Otherwise we have a new value. Parse it into the internal
1734 unsigned int oldvincorelen = 0;
1737 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1740 oldvincorelen = xd->len;
1742 id = seen[*keyp] - 1;
1745 case REPOKEY_TYPE_VOID:
1746 case REPOKEY_TYPE_CONSTANT:
1747 case REPOKEY_TYPE_CONSTANTID:
1749 case REPOKEY_TYPE_STR:
1750 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1752 case REPOKEY_TYPE_MD5:
1753 data_addblob(xd, data->attrdata + id, SIZEOF_MD5);
1755 case REPOKEY_TYPE_SHA1:
1756 data_addblob(xd, data->attrdata + id, SIZEOF_SHA1);
1758 case REPOKEY_TYPE_ID:
1759 case REPOKEY_TYPE_NUM:
1760 case REPOKEY_TYPE_DIR:
1763 case REPOKEY_TYPE_IDARRAY:
1764 for (ida = data->attriddata + id; *ida; ida++)
1765 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
1767 case REPOKEY_TYPE_DIRNUMNUMARRAY:
1768 for (ida = data->attriddata + id; *ida; ida += 3)
1770 data_addid(xd, ida[0]);
1771 data_addid(xd, ida[1]);
1772 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1775 case REPOKEY_TYPE_DIRSTRARRAY:
1776 for (ida = data->attriddata + id; *ida; ida += 2)
1778 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1779 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1783 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1786 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1788 /* put offset/len in incore */
1789 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1790 oldvincorelen = xd->len - oldvincorelen;
1791 data_addid(&newincore, oldvincorelen);
1796 if (entry < 0 && data->extraattrs[-1 - entry])
1797 sat_free(data->extraattrs[-1 - entry]);
1798 else if (entry >= 0 && data->attrs[entry])
1799 sat_free(data->attrs[entry]);
1804 sat_free(data->incoredata);
1805 data->incoredata = newincore.buf;
1806 data->incoredatalen = newincore.len;
1807 data->incoredatafree = 0;
1809 sat_free(data->vincore);
1810 data->vincore = newvincore.buf;
1811 data->vincorelen = newvincore.len;
1813 data->attrs = sat_free(data->attrs);
1814 data->extraattrs = sat_free(data->extraattrs);
1815 data->attrdata = sat_free(data->attrdata);
1816 data->attriddata = sat_free(data->attriddata);
1817 data->attrdatalen = 0;
1818 data->attriddatalen = 0;
1822 repodata_str2dir(Repodata *data, const char *dir, int create)
1828 while (*dir == '/' && dir[1] == '/')
1830 if (*dir == '/' && !dir[1])
1834 dire = strchrnul(dir, '/');
1835 if (data->localpool)
1836 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1838 id = strn2id(data->repo->pool, dir, dire - dir, create);
1841 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1854 repodata_dir2str(Repodata *data, Id did, const char *suf)
1856 Pool *pool = data->repo->pool;
1863 return suf ? suf : "";
1867 comp = dirpool_compid(&data->dirpool, parent);
1868 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
1870 parent = dirpool_parent(&data->dirpool, parent);
1875 l += strlen(suf) + 1;
1876 p = pool_alloctmpspace(pool, l + 1) + l;
1887 comp = dirpool_compid(&data->dirpool, parent);
1888 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
1891 strncpy(p, comps, l);
1892 parent = dirpool_parent(&data->dirpool, parent);
1900 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1902 return compress_buf(page, len, cpage, max);
1905 #define SOLV_ERROR_EOF 3
1907 static inline unsigned int
1913 for (i = 0; i < 4; i++)
1923 #define SOLV_ERROR_EOF 3
1924 #define SOLV_ERROR_CORRUPT 6
1926 /* Try to either setup on-demand paging (using FP as backing
1927 file), or in case that doesn't work (FP not seekable) slurps in
1928 all pages and deactivates paging. */
1930 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1932 FILE *fp = data->fp;
1933 unsigned int npages;
1935 unsigned int can_seek;
1937 unsigned char buf[BLOB_PAGESIZE];
1939 if (pagesz != BLOB_PAGESIZE)
1941 /* We could handle this by slurping in everything. */
1942 data->error = SOLV_ERROR_CORRUPT;
1946 if ((cur_file_ofs = ftell(fp)) < 0)
1950 data->pagefd = dup(fileno(fp));
1951 if (data->pagefd == -1)
1955 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1957 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1959 data->num_pages = npages;
1960 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1962 /* If we can't seek on our input we have to slurp in everything. */
1964 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1965 for (i = 0; i < npages; i++)
1967 unsigned int in_len = read_u32(fp);
1968 unsigned int compressed = in_len & 1;
1969 Attrblobpage *p = data->pages + i;
1972 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1973 i, in_len, compressed ? "" : "not ");
1979 p->file_offset = cur_file_ofs;
1980 p->file_size = in_len * 2 + compressed;
1981 if (fseek(fp, in_len, SEEK_CUR) < 0)
1984 fprintf (stderr, "can't seek after we thought we can\n");
1985 /* We can't fall back to non-seeking behaviour as we already
1986 read over some data pages without storing them away. */
1987 data->error = SOLV_ERROR_EOF;
1988 close(data->pagefd);
1992 cur_file_ofs += in_len;
1996 unsigned int out_len;
1997 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1998 p->mapped_at = i * BLOB_PAGESIZE;
2001 /* We can't seek, so suck everything in. */
2002 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
2005 data->error = SOLV_ERROR_EOF;
2010 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
2011 if (out_len != BLOB_PAGESIZE && i < npages - 1)
2013 data->error = SOLV_ERROR_CORRUPT;
2022 repodata_disable_paging(Repodata *data)
2024 if (maybe_load_repodata(data, 0)
2026 load_page_range (data, 0, data->num_pages - 1);
2029 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: