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 get_new_struct(Repodata *data)
1125 /* Make sure to never give out struct id 0. */
1128 data->structs = sat_extend(0, 0, 2, sizeof(Id *), REPODATA_BLOCK);
1129 data->structs[0] = 0;
1130 data->structs[1] = 0;
1134 data->structs = sat_extend(data->structs, data->nstructs, 1, sizeof(Id *), REPODATA_BLOCK);
1135 data->structs[data->nstructs] = 0;
1136 return data->nstructs++;
1140 repodata_get_handle_int(Repodata *data, Id entry)
1143 if (!data->attrs && entry >= 0)
1145 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id),
1148 else if (!data->extraattrs && entry < 0)
1149 data->extraattrs = sat_calloc_block(data->nextra, sizeof(Id), REPODATA_BLOCK);
1151 ap = &data->extraattrs[-1 - entry];
1153 ap = &data->attrs[entry];
1155 *ap = get_new_struct(data);
1160 repodata_get_handle(Repodata *data, Id entry)
1162 return repodata_get_handle_int(data, entry);
1166 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1171 ap = data->structs[handle];
1175 for (pp = ap; *pp; pp += 2)
1176 /* Determine equality based on the name only, allows us to change
1177 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1178 if (data->keys[*pp].name == data->keys[keyid].name)
1191 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1192 data->structs[handle] = ap;
1200 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1204 /* find key in keys */
1205 for (keyid = 1; keyid < data->nkeys; keyid++)
1206 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
1208 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
1212 if (keyid == data->nkeys)
1214 /* allocate new key */
1215 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
1216 data->keys[data->nkeys++] = *key;
1217 if (data->verticaloffset)
1219 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
1220 data->verticaloffset[data->nkeys - 1] = 0;
1223 repodata_insert_keyid(data, handle, keyid, val, 1);
1227 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1231 key.type = REPOKEY_TYPE_ID;
1233 key.storage = KEY_STORAGE_INCORE;
1234 repodata_set(data, handle, &key, id);
1238 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1242 key.type = REPOKEY_TYPE_NUM;
1244 key.storage = KEY_STORAGE_INCORE;
1245 repodata_set(data, handle, &key, (Id)num);
1249 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1253 if (data->localpool)
1254 id = stringpool_str2id(&data->spool, str, 1);
1256 id = str2id(data->repo->pool, str, 1);
1258 key.type = REPOKEY_TYPE_ID;
1260 key.storage = KEY_STORAGE_INCORE;
1261 repodata_set(data, handle, &key, id);
1265 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1269 key.type = REPOKEY_TYPE_CONSTANT;
1270 key.size = constant;
1271 key.storage = KEY_STORAGE_INCORE;
1272 repodata_set(data, handle, &key, 0);
1276 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
1280 key.type = REPOKEY_TYPE_CONSTANTID;
1282 key.storage = KEY_STORAGE_INCORE;
1283 repodata_set(data, handle, &key, 0);
1287 repodata_set_void(Repodata *data, Id handle, Id keyname)
1291 key.type = REPOKEY_TYPE_VOID;
1293 key.storage = KEY_STORAGE_INCORE;
1294 repodata_set(data, handle, &key, 0);
1298 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
1303 l = strlen(str) + 1;
1305 key.type = REPOKEY_TYPE_STR;
1307 key.storage = KEY_STORAGE_INCORE;
1308 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1309 memcpy(data->attrdata + data->attrdatalen, str, l);
1310 repodata_set(data, handle, &key, data->attrdatalen);
1311 data->attrdatalen += l;
1315 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1320 pp = data->structs[handle];
1322 for (; *pp; pp += 2)
1323 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1327 /* not found. allocate new key */
1332 key.storage = KEY_STORAGE_INCORE;
1333 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1334 repodata_set(data, handle, &key, data->attriddatalen);
1338 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1339 oldsize += entrysize;
1340 if (ida + 1 == data->attriddata + data->attriddatalen)
1342 /* this was the last entry, just append it */
1343 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1344 data->attriddatalen--; /* overwrite terminating 0 */
1348 /* too bad. move to back. */
1349 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1350 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1351 pp[1] = data->attriddatalen;
1352 data->attriddatalen += oldsize;
1357 checksumtype2len(Id type)
1361 case REPOKEY_TYPE_MD5:
1363 case REPOKEY_TYPE_SHA1:
1365 case REPOKEY_TYPE_SHA256:
1366 return SIZEOF_SHA256;
1373 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
1374 const unsigned char *str)
1377 int l = checksumtype2len(type);
1384 key.storage = KEY_STORAGE_INCORE;
1385 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1386 memcpy(data->attrdata + data->attrdatalen, str, l);
1387 repodata_set(data, handle, &key, data->attrdatalen);
1388 data->attrdatalen += l;
1392 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1395 for (i = 0; i < buflen; i++)
1397 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1398 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
1399 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
1410 buf[i] = (buf[i] << 4) | v;
1417 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
1420 unsigned char buf[64];
1421 int l = checksumtype2len(type);
1425 if (hexstr2bytes(buf, str, l) != l)
1427 fprintf(stderr, "Invalid hex character in '%s'\n", str);
1430 repodata_set_bin_checksum(data, handle, keyname, type, buf);
1434 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1439 l = checksumtype2len(type);
1442 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1443 for (i = 0; i < l; i++)
1445 unsigned char v = buf[i];
1446 unsigned char w = v >> 4;
1447 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1449 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1456 repodata_globalize_id(Repodata *data, Id id)
1458 if (!data || !data->localpool)
1460 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
1464 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
1468 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
1470 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1471 data->attriddata[data->attriddatalen++] = dir;
1472 data->attriddata[data->attriddatalen++] = num;
1473 data->attriddata[data->attriddatalen++] = num2;
1474 data->attriddata[data->attriddatalen++] = 0;
1478 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
1484 l = strlen(str) + 1;
1485 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1486 memcpy(data->attrdata + data->attrdatalen, str, l);
1487 stroff = data->attrdatalen;
1488 data->attrdatalen += l;
1491 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
1493 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1494 data->attriddata[data->attriddatalen++] = dir;
1495 data->attriddata[data->attriddatalen++] = stroff;
1496 data->attriddata[data->attriddatalen++] = 0;
1500 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
1503 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
1505 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
1506 data->attriddata[data->attriddatalen++] = id;
1507 data->attriddata[data->attriddatalen++] = 0;
1511 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
1515 if (data->localpool)
1516 id = stringpool_str2id(&data->spool, str, 1);
1518 id = str2id(data->repo->pool, str, 1);
1519 repodata_add_idarray(data, handle, keyname, id);
1523 repodata_create_struct(Repodata *data, Id handle, Id keyname)
1525 Id newhandle = get_new_struct(data);
1526 repodata_add_idarray(data, handle, keyname, newhandle);
1531 repodata_merge_attrs(Repodata *data, Id dest, Id src)
1535 || !(keyp = data->structs[src < 0
1536 ? data->extraattrs[-1 - src]
1537 : data->attrs[src]]))
1539 dest = repodata_get_handle_int(data, dest);
1540 for (; *keyp; keyp += 2)
1541 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
1544 /*********************************/
1546 /* unify with repo_write! */
1548 #define EXTDATA_BLOCK 1023
1549 #define SCHEMATA_BLOCK 31
1550 #define SCHEMATADATA_BLOCK 255
1558 data_addid(struct extdata *xd, Id x)
1561 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
1562 dp = xd->buf + xd->len;
1567 *dp++ = (x >> 28) | 128;
1569 *dp++ = (x >> 21) | 128;
1570 *dp++ = (x >> 14) | 128;
1573 *dp++ = (x >> 7) | 128;
1575 xd->len = dp - xd->buf;
1579 data_addideof(struct extdata *xd, Id x, int eof)
1582 x = (x & 63) | ((x & ~63) << 1);
1583 data_addid(xd, (eof ? x: x | 64));
1587 data_addblob(struct extdata *xd, unsigned char *blob, int len)
1589 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
1590 memcpy(xd->buf + xd->len, blob, len);
1594 /*********************************/
1597 addschema_prepare(Repodata *data, Id *schematacache)
1602 memset(schematacache, 0, 256 * sizeof(Id));
1603 for (i = 0; i < data->nschemata; i++)
1605 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
1608 schematacache[h] = i + 1;
1610 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
1611 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
1615 addschema(Repodata *data, Id *schema, Id *schematacache)
1620 for (sp = schema, len = 0, h = 0; *sp; len++)
1625 cid = schematacache[h];
1629 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
1631 /* cache conflict */
1632 for (cid = 0; cid < data->nschemata; cid++)
1633 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
1636 /* a new one. make room. */
1637 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
1638 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
1640 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
1641 data->schemata[data->nschemata] = data->schemadatalen;
1642 data->schemadatalen += len;
1643 schematacache[h] = data->nschemata + 1;
1645 fprintf(stderr, "addschema: new schema\n");
1647 return data->nschemata++;
1652 repodata_internalize(Repodata *data)
1655 Id id, entry, nentry, *ida;
1656 Id schematacache[256];
1657 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
1658 unsigned char *dp, *ndp;
1659 int newschema, oldcount;
1660 struct extdata newincore;
1661 struct extdata newvincore;
1663 if (!data->attrs && !data->extraattrs)
1666 newvincore.buf = data->vincore;
1667 newvincore.len = data->vincorelen;
1669 schema = sat_malloc2(data->nkeys, sizeof(Id));
1670 seen = sat_malloc2(data->nkeys, sizeof(Id));
1672 /* Merge the data already existing (in data->schemata, ->incoredata and
1673 friends) with the new attributes in data->attrs[]. */
1674 nentry = data->end - data->start;
1675 addschema_prepare(data, schematacache);
1676 memset(&newincore, 0, sizeof(newincore));
1677 data_addid(&newincore, 0);
1680 for (entry = data->extraattrs ? -data->nextra : 0; entry < nentry; entry++)
1683 memset(seen, 0, data->nkeys * sizeof(Id));
1685 dp = entry2data(data, entry);
1686 if (data->incoredata)
1687 dp = data_read_id(dp, &oldschema);
1691 fprintf(stderr, "oldschema %d\n", oldschema);
1692 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
1693 fprintf(stderr, "schemadata %p\n", data->schemadata);
1695 /* seen: -1: old data 0: skipped >0: id + 1 */
1698 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
1702 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
1709 handle = entry < 0 ? data->extraattrs[-1 - entry] : data->attrs[entry];
1710 keyp = data->structs[handle];
1712 for (; *keyp; keyp += 2)
1719 seen[*keyp] = keyp[1] + 1;
1723 /* Ideally we'd like to sort the new schema here, to ensure
1724 schema equality independend of the ordering. We can't do that
1725 yet. For once see below (old ids need to come before new ids).
1726 An additional difficulty is that we also need to move
1727 the values with the keys. */
1728 schemaid = addschema(data, schema, schematacache);
1730 schemaid = oldschema;
1733 /* Now create data blob. We walk through the (possibly new) schema
1734 and either copy over old data, or insert the new. */
1735 /* XXX Here we rely on the fact that the (new) schema has the form
1736 o1 o2 o3 o4 ... | n1 n2 n3 ...
1737 (oX being the old keyids (possibly overwritten), and nX being
1738 the new keyids). This rules out sorting the keyids in order
1739 to ensure a small schema count. */
1741 data->extraoffset[-1 - entry] = newincore.len;
1743 data->incoreoffset[entry] = newincore.len;
1744 data_addid(&newincore, schemaid);
1745 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
1747 key = data->keys + *keyp;
1751 /* Skip the data associated with this old key. */
1752 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1754 ndp = data_skip(dp, REPOKEY_TYPE_ID);
1755 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
1757 else if (key->storage == KEY_STORAGE_INCORE)
1758 ndp = data_skip(dp, key->type);
1761 if (seen[*keyp] == -1)
1763 /* If this key was an old one _and_ was not overwritten with
1764 a different value copy over the old value (we skipped it
1767 data_addblob(&newincore, dp, ndp - dp);
1770 else if (seen[*keyp])
1772 /* Otherwise we have a new value. Parse it into the internal
1775 unsigned int oldvincorelen = 0;
1778 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1781 oldvincorelen = xd->len;
1783 id = seen[*keyp] - 1;
1786 case REPOKEY_TYPE_VOID:
1787 case REPOKEY_TYPE_CONSTANT:
1788 case REPOKEY_TYPE_CONSTANTID:
1790 case REPOKEY_TYPE_STR:
1791 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1793 case REPOKEY_TYPE_MD5:
1794 data_addblob(xd, data->attrdata + id, SIZEOF_MD5);
1796 case REPOKEY_TYPE_SHA1:
1797 data_addblob(xd, data->attrdata + id, SIZEOF_SHA1);
1799 case REPOKEY_TYPE_ID:
1800 case REPOKEY_TYPE_NUM:
1801 case REPOKEY_TYPE_DIR:
1804 case REPOKEY_TYPE_IDARRAY:
1805 for (ida = data->attriddata + id; *ida; ida++)
1806 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
1808 case REPOKEY_TYPE_DIRNUMNUMARRAY:
1809 for (ida = data->attriddata + id; *ida; ida += 3)
1811 data_addid(xd, ida[0]);
1812 data_addid(xd, ida[1]);
1813 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1816 case REPOKEY_TYPE_DIRSTRARRAY:
1817 for (ida = data->attriddata + id; *ida; ida += 2)
1819 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1820 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1824 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1827 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1829 /* put offset/len in incore */
1830 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1831 oldvincorelen = xd->len - oldvincorelen;
1832 data_addid(&newincore, oldvincorelen);
1837 if (data->structs[handle])
1838 data->structs[handle] = sat_free(data->structs[handle]);
1840 for (entry = 0; entry < data->nstructs; entry++)
1841 if (data->structs[entry])
1842 sat_free(data->structs[entry]);
1843 data->structs = sat_free(data->structs);
1847 sat_free(data->incoredata);
1848 data->incoredata = newincore.buf;
1849 data->incoredatalen = newincore.len;
1850 data->incoredatafree = 0;
1852 sat_free(data->vincore);
1853 data->vincore = newvincore.buf;
1854 data->vincorelen = newvincore.len;
1856 data->attrs = sat_free(data->attrs);
1857 data->extraattrs = sat_free(data->extraattrs);
1858 data->attrdata = sat_free(data->attrdata);
1859 data->attriddata = sat_free(data->attriddata);
1860 data->attrdatalen = 0;
1861 data->attriddatalen = 0;
1865 repodata_str2dir(Repodata *data, const char *dir, int create)
1871 while (*dir == '/' && dir[1] == '/')
1873 if (*dir == '/' && !dir[1])
1877 dire = strchrnul(dir, '/');
1878 if (data->localpool)
1879 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1881 id = strn2id(data->repo->pool, dir, dire - dir, create);
1884 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1897 repodata_dir2str(Repodata *data, Id did, const char *suf)
1899 Pool *pool = data->repo->pool;
1906 return suf ? suf : "";
1910 comp = dirpool_compid(&data->dirpool, parent);
1911 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
1913 parent = dirpool_parent(&data->dirpool, parent);
1918 l += strlen(suf) + 1;
1919 p = pool_alloctmpspace(pool, l + 1) + l;
1930 comp = dirpool_compid(&data->dirpool, parent);
1931 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
1934 strncpy(p, comps, l);
1935 parent = dirpool_parent(&data->dirpool, parent);
1943 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1945 return compress_buf(page, len, cpage, max);
1948 #define SOLV_ERROR_EOF 3
1950 static inline unsigned int
1956 for (i = 0; i < 4; i++)
1966 #define SOLV_ERROR_EOF 3
1967 #define SOLV_ERROR_CORRUPT 6
1969 /* Try to either setup on-demand paging (using FP as backing
1970 file), or in case that doesn't work (FP not seekable) slurps in
1971 all pages and deactivates paging. */
1973 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1975 FILE *fp = data->fp;
1976 unsigned int npages;
1978 unsigned int can_seek;
1980 unsigned char buf[BLOB_PAGESIZE];
1982 if (pagesz != BLOB_PAGESIZE)
1984 /* We could handle this by slurping in everything. */
1985 data->error = SOLV_ERROR_CORRUPT;
1989 if ((cur_file_ofs = ftell(fp)) < 0)
1993 data->pagefd = dup(fileno(fp));
1994 if (data->pagefd == -1)
1998 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
2000 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
2002 data->num_pages = npages;
2003 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
2005 /* If we can't seek on our input we have to slurp in everything. */
2007 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
2008 for (i = 0; i < npages; i++)
2010 unsigned int in_len = read_u32(fp);
2011 unsigned int compressed = in_len & 1;
2012 Attrblobpage *p = data->pages + i;
2015 fprintf (stderr, "page %d: len %d (%scompressed)\n",
2016 i, in_len, compressed ? "" : "not ");
2022 p->file_offset = cur_file_ofs;
2023 p->file_size = in_len * 2 + compressed;
2024 if (fseek(fp, in_len, SEEK_CUR) < 0)
2027 fprintf (stderr, "can't seek after we thought we can\n");
2028 /* We can't fall back to non-seeking behaviour as we already
2029 read over some data pages without storing them away. */
2030 data->error = SOLV_ERROR_EOF;
2031 close(data->pagefd);
2035 cur_file_ofs += in_len;
2039 unsigned int out_len;
2040 void *dest = data->blob_store + i * BLOB_PAGESIZE;
2041 p->mapped_at = i * BLOB_PAGESIZE;
2044 /* We can't seek, so suck everything in. */
2045 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
2048 data->error = SOLV_ERROR_EOF;
2053 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
2054 if (out_len != BLOB_PAGESIZE && i < npages - 1)
2056 data->error = SOLV_ERROR_CORRUPT;
2065 repodata_disable_paging(Repodata *data)
2067 if (maybe_load_repodata(data, 0)
2069 load_page_range (data, 0, data->num_pages - 1);
2072 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: