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
25 #include "poolid_private.h"
28 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
29 unsigned char *out, unsigned int out_len);
30 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
33 unsigned int out_len);
35 static unsigned char *
36 data_read_id(unsigned char *dp, Id *idp)
48 x = (x << 7) ^ c ^ 128;
52 static unsigned char *
53 data_read_ideof(unsigned char *dp, Id *idp, int *eof)
72 x = (x << 7) ^ c ^ 128;
76 static unsigned char *
77 data_skip(unsigned char *dp, int type)
88 while ((*dp & 0x80) != 0)
92 while ((*dp & 0xc0) != 0)
99 case TYPE_DIRSTRARRAY:
102 while ((*dp & 0x80) != 0)
111 case TYPE_DIRNUMNUMARRAY:
114 while ((*dp & 0x80) != 0)
117 while ((*dp & 0x80) != 0)
120 while ((*dp & 0x80) != 0)
127 fprintf(stderr, "unknown type in data_skip\n");
132 static unsigned char *
133 data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
146 kv->str = (const char *)dp;
147 return dp + strlen(kv->str) + 1;
149 return data_read_id(dp, &kv->id);
151 return data_read_id(dp, &kv->num);
153 return data_read_ideof(dp, &kv->id, &kv->eof);
155 return data_read_id(dp, &kv->id);
156 case TYPE_DIRSTRARRAY:
157 dp = data_read_ideof(dp, &kv->id, &kv->eof);
158 kv->str = (const char *)dp;
159 return dp + strlen(kv->str) + 1;
160 case TYPE_DIRNUMNUMARRAY:
161 dp = data_read_id(dp, &kv->id);
162 dp = data_read_id(dp, &kv->num);
163 return data_read_ideof(dp, &kv->num2, &kv->eof);
169 static unsigned char *
170 forward_to_key(Repodata *data, Id key, Id schemaid, unsigned char *dp)
174 keyp = data->schemadata + data->schemata[schemaid];
175 while ((k = *keyp++) != 0)
179 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
181 dp = data_skip(dp, TYPE_ID); /* skip that offset */
182 dp = data_skip(dp, TYPE_ID); /* skip that length */
185 if (data->keys[k].storage != KEY_STORAGE_INCORE)
187 dp = data_skip(dp, data->keys[k].type);
192 #define BLOB_PAGEBITS 15
193 #define BLOB_PAGESIZE (1 << BLOB_PAGEBITS)
195 static unsigned char *
196 load_page_range(Repodata *data, unsigned int pstart, unsigned int pend)
198 /* Make sure all pages from PSTART to PEND (inclusive) are loaded,
199 and are consecutive. Return a pointer to the mapping of PSTART. */
200 unsigned char buf[BLOB_PAGESIZE];
203 /* Quick check in case all pages are there already and consecutive. */
204 for (i = pstart; i <= pend; i++)
205 if (data->pages[i].mapped_at == -1
207 && data->pages[i].mapped_at
208 != data->pages[i-1].mapped_at + BLOB_PAGESIZE))
211 return data->blob_store + data->pages[pstart].mapped_at;
213 /* Ensure that we can map the numbers of pages we need at all. */
214 if (pend - pstart + 1 > data->ncanmap)
216 unsigned int oldcan = data->ncanmap;
217 data->ncanmap = pend - pstart + 1;
218 if (data->ncanmap < 4)
220 data->mapped = sat_realloc2(data->mapped, data->ncanmap, sizeof(data->mapped[0]));
221 memset (data->mapped + oldcan, 0, (data->ncanmap - oldcan) * sizeof (data->mapped[0]));
222 data->blob_store = sat_realloc2(data->blob_store, data->ncanmap, BLOB_PAGESIZE);
224 fprintf (stderr, "PAGE: can map %d pages\n", data->ncanmap);
228 /* Now search for "cheap" space in our store. Space is cheap if it's either
229 free (very cheap) or contains pages we search for anyway. */
231 /* Setup cost array. */
232 unsigned int cost[data->ncanmap];
233 for (i = 0; i < data->ncanmap; i++)
235 unsigned int pnum = data->mapped[i];
241 Attrblobpage *p = data->pages + pnum;
242 assert (p->mapped_at != -1);
243 if (pnum >= pstart && pnum <= pend)
250 /* And search for cheapest space. */
251 unsigned int best_cost = -1;
252 unsigned int best = 0;
253 unsigned int same_cost = 0;
254 for (i = 0; i + pend - pstart < data->ncanmap; i++)
256 unsigned int c = cost[i];
258 for (j = 0; j < pend - pstart + 1; j++)
261 best_cost = c, best = i;
262 else if (c == best_cost)
264 /* A null cost won't become better. */
268 /* If all places have the same cost we would thrash on slot 0. Avoid
269 this by doing a round-robin strategy in this case. */
270 if (same_cost == data->ncanmap - pend + pstart - 1)
271 best = data->rr_counter++ % (data->ncanmap - pend + pstart);
273 /* So we want to map our pages from [best] to [best+pend-pstart].
274 Use a very simple strategy, which doesn't make the best use of
275 our resources, but works. Throw away all pages in that range
276 (even ours) then copy around ours (in case they were outside the
277 range) or read them in. */
278 for (i = best; i < best + pend - pstart + 1; i++)
280 unsigned int pnum = data->mapped[i];
282 /* If this page is exactly at the right place already,
283 no need to evict it. */
284 && pnum != pstart + i - best)
286 /* Evict this page. */
288 fprintf (stderr, "PAGE: evict page %d from %d\n", pnum, i);
292 data->pages[pnum].mapped_at = -1;
296 /* Everything is free now. Read in the pages we want. */
297 for (i = pstart; i <= pend; i++)
299 Attrblobpage *p = data->pages + i;
300 unsigned int pnum = i - pstart + best;
301 void *dest = data->blob_store + pnum * BLOB_PAGESIZE;
302 if (p->mapped_at != -1)
304 if (p->mapped_at != pnum * BLOB_PAGESIZE)
307 fprintf (stderr, "PAGECOPY: %d to %d\n", i, pnum);
309 /* Still mapped somewhere else, so just copy it from there. */
310 memcpy (dest, data->blob_store + p->mapped_at, BLOB_PAGESIZE);
311 data->mapped[p->mapped_at / BLOB_PAGESIZE] = 0;
316 unsigned int in_len = p->file_size;
317 unsigned int compressed = in_len & 1;
320 fprintf (stderr, "PAGEIN: %d to %d", i, pnum);
322 /* Not mapped, so read in this page. */
323 if (fseek(data->fp, p->file_offset, SEEK_SET) < 0)
325 perror ("mapping fseek");
328 if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1)
330 perror ("mapping fread");
335 unsigned int out_len;
336 out_len = unchecked_decompress_buf(buf, in_len,
337 dest, BLOB_PAGESIZE);
338 if (out_len != BLOB_PAGESIZE
339 && i < data->num_pages - 1)
341 fprintf (stderr, "can't decompress\n");
345 fprintf (stderr, " (expand %d to %d)", in_len, out_len);
349 fprintf (stderr, "\n");
352 p->mapped_at = pnum * BLOB_PAGESIZE;
353 data->mapped[pnum] = i + 1;
355 return data->blob_store + best * BLOB_PAGESIZE;
358 static unsigned char *
359 make_vertical_available(Repodata *data, Repokey *key, Id off, Id len)
362 if (key->type == TYPE_VOID)
364 if (off >= data->lastverticaloffset)
366 off -= data->lastverticaloffset;
367 if (off + len > data->vincorelen)
369 return data->vincore + off;
373 if (off + len > key->size)
375 /* we now have the offset, go into vertical */
376 off += data->verticaloffset[key - data->keys];
377 dp = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
379 dp += off % BLOB_PAGESIZE;
383 static inline unsigned char *
384 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
386 unsigned char *dp = *dpp;
390 if (key->storage == KEY_STORAGE_INCORE)
392 /* hmm, this is a bit expensive */
393 *dpp = data_skip(dp, key->type);
396 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
399 dp = data_read_id(dp, &off);
400 dp = data_read_id(dp, &len);
402 return make_vertical_available(data, key, off, len);
408 maybe_load_repodata(Repodata *data)
410 if (data->state == REPODATA_STUB)
412 if (data->loadcallback)
413 data->loadcallback(data);
415 data->state = REPODATA_ERROR;
417 if (data->state == REPODATA_AVAILABLE)
419 data->state = REPODATA_ERROR;
424 repodata_lookup_str(Repodata *data, Id entry, Id keyid)
431 if (!maybe_load_repodata (data))
434 dp = data->incoredata + data->incoreoffset[entry];
435 dp = data_read_id(dp, &schema);
436 /* make sure the schema of this solvable contains the key */
437 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
440 dp = forward_to_key(data, keyid, schema, dp);
441 key = data->keys + keyid;
442 dp = get_data(data, key, &dp);
445 if (key->type == TYPE_STR)
446 return (const char *)dp;
447 if (key->type != TYPE_ID)
449 /* id type, must either use global or local string store*/
450 dp = data_read_id(dp, &id);
452 return data->spool.stringspace + data->spool.strings[id];
453 return id2str(data->repo->pool, id);
457 repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned *value)
467 if (!maybe_load_repodata (data))
470 dp = data->incoredata + data->incoreoffset[entry];
471 dp = data_read_id(dp, &schema);
472 /* make sure the schema of this solvable contains the key */
473 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
476 dp = forward_to_key(data, keyid, schema, dp);
477 key = data->keys + keyid;
478 dp = get_data(data, key, &dp);
481 if (key->type == TYPE_NUM
482 || key->type == TYPE_U32
483 || key->type == TYPE_CONSTANT)
485 dp = data_fetch(dp, &kv, key);
493 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
497 Id k, keyid, *kp, *keyp;
498 unsigned char *dp, *ddp;
503 if (!maybe_load_repodata (data))
506 dp = data->incoredata + data->incoreoffset[entry];
507 dp = data_read_id(dp, &schema);
508 keyp = data->schemadata + data->schemata[schema];
511 /* search in a specific key */
512 for (kp = keyp; (k = *kp++) != 0; )
513 if (data->keys[k].name == keyname)
517 dp = forward_to_key(data, k, schema, dp);
523 while ((keyid = *keyp++) != 0)
526 key = data->keys + keyid;
527 ddp = get_data(data, key, &dp);
530 ddp = data_fetch(ddp, &kv, key);
533 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
535 while (!kv.eof && !stop);
536 if (onekey || stop > SEARCH_NEXT_KEY)
542 /* extend repodata so that it includes solvables p */
544 repodata_extend(Repodata *data, Id p)
546 if (data->start == data->end)
547 data->start = data->end = p;
550 int old = data->end - data->start;
551 int new = p - data->end + 1;
554 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
555 memset(data->attrs + old, 0, new * sizeof(Id *));
557 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
558 memset(data->incoreoffset + old, 0, new * sizeof(Id));
563 int old = data->end - data->start;
564 int new = data->start - p;
567 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
568 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
569 memset(data->attrs, 0, new * sizeof(Id *));
571 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
572 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
573 memset(data->incoreoffset, 0, new * sizeof(Id));
579 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
584 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
586 if (data->attrs[entry])
588 for (pp = data->attrs[entry]; *pp; pp += 2)
589 /* Determine equality based on the name only, allows us to change
590 type (when overwrite is set), and makes TYPE_CONSTANT work. */
591 if (data->keys[*pp].name == data->keys[keyid].name)
602 i = pp - data->attrs[entry];
604 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
605 pp = data->attrs[entry] + i;
612 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
616 /* find key in keys */
617 for (keyid = 1; keyid < data->nkeys; keyid++)
618 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
620 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
624 if (keyid == data->nkeys)
626 /* allocate new key */
627 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
628 data->keys[data->nkeys++] = *key;
629 if (data->verticaloffset)
631 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
632 data->verticaloffset[data->nkeys - 1] = 0;
635 repodata_insert_keyid(data, entry, keyid, val, 1);
639 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
645 key.storage = KEY_STORAGE_INCORE;
646 repodata_set(data, entry, &key, id);
650 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
656 key.storage = KEY_STORAGE_INCORE;
657 repodata_set(data, entry, &key, num);
661 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
666 id = stringpool_str2id(&data->spool, str, 1);
668 id = str2id(data->repo->pool, str, 1);
672 key.storage = KEY_STORAGE_INCORE;
673 repodata_set(data, entry, &key, id);
677 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
681 key.type = TYPE_CONSTANT;
683 key.storage = KEY_STORAGE_INCORE;
684 repodata_set(data, entry, &key, 0);
688 repodata_set_void(Repodata *data, Id entry, Id keyname)
692 key.type = TYPE_VOID;
694 key.storage = KEY_STORAGE_INCORE;
695 repodata_set(data, entry, &key, 0);
699 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
708 key.storage = KEY_STORAGE_INCORE;
709 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
710 memcpy(data->attrdata + data->attrdatalen, str, l);
711 repodata_set(data, entry, &key, data->attrdatalen);
712 data->attrdatalen += l;
716 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
722 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
724 if (data->attrs && data->attrs[entry])
726 for (pp = data->attrs[entry]; *pp; pp += 2)
727 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
732 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
734 if (ida + 1 == data->attriddata + data->attriddatalen)
736 /* this was the last entry, just append it */
737 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
738 data->attriddatalen--; /* overwrite terminating 0 */
742 /* too bad. move to back. */
743 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
744 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
745 pp[1] = data->attriddatalen;
746 data->attriddatalen += oldsize;
748 data->attriddata[data->attriddatalen++] = dir;
749 data->attriddata[data->attriddatalen++] = num;
750 data->attriddata[data->attriddatalen++] = num2;
751 data->attriddata[data->attriddatalen++] = 0;
756 key.type = TYPE_DIRNUMNUMARRAY;
758 key.storage = KEY_STORAGE_INCORE;
759 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
760 repodata_set(data, entry, &key, data->attriddatalen);
761 data->attriddata[data->attriddatalen++] = dir;
762 data->attriddata[data->attriddatalen++] = num;
763 data->attriddata[data->attriddatalen++] = num2;
764 data->attriddata[data->attriddatalen++] = 0;
768 repodata_merge_attrs (Repodata *data, Id dest, Id src)
771 for (keyp = data->attrs[src]; *keyp; keyp += 2)
772 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
775 /*********************************/
777 /* unify with repo_write! */
779 #define EXTDATA_BLOCK 1023
780 #define SCHEMATA_BLOCK 31
781 #define SCHEMATADATA_BLOCK 255
789 data_addid(struct extdata *xd, Id x)
792 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
793 dp = xd->buf + xd->len;
798 *dp++ = (x >> 28) | 128;
800 *dp++ = (x >> 21) | 128;
801 *dp++ = (x >> 14) | 128;
804 *dp++ = (x >> 7) | 128;
806 xd->len = dp - xd->buf;
810 data_addideof(struct extdata *xd, Id x, int eof)
813 x = (x & 63) | ((x & ~63) << 1);
814 data_addid(xd, (eof ? x: x | 64));
818 data_addblob(struct extdata *xd, unsigned char *blob, int len)
820 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
821 memcpy(xd->buf + xd->len, blob, len);
825 /*********************************/
828 addschema_prepare(Repodata *data, Id *schematacache)
833 memset(schematacache, 0, 256 * sizeof(Id));
834 for (i = 0; i < data->nschemata; i++)
836 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
839 schematacache[h] = i + 1;
841 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
842 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
846 addschema(Repodata *data, Id *schema, Id *schematacache)
851 for (sp = schema, len = 0, h = 0; *sp; len++)
856 cid = schematacache[h];
860 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
863 for (cid = 0; cid < data->nschemata; cid++)
864 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
867 /* a new one. make room. */
868 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
869 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
871 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
872 data->schemata[data->nschemata] = data->schemadatalen;
873 data->schemadatalen += len;
874 schematacache[h] = data->nschemata + 1;
876 fprintf(stderr, "addschema: new schema\n");
878 return data->nschemata++;
883 repodata_internalize(Repodata *data)
886 Id id, entry, nentry, *ida;
887 Id schematacache[256];
888 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
889 unsigned char *dp, *ndp;
890 int newschema, oldcount;
891 struct extdata newincore;
892 struct extdata newvincore;
897 newvincore.buf = data->vincore;
898 newvincore.len = data->vincorelen;
900 schema = sat_malloc2(data->nkeys, sizeof(Id));
901 seen = sat_malloc2(data->nkeys, sizeof(Id));
903 /* Merge the data already existing (in data->schemata, ->incoredata and
904 friends) with the new attributes in data->attrs[]. */
905 nentry = data->end - data->start;
906 addschema_prepare(data, schematacache);
907 memset(&newincore, 0, sizeof(newincore));
908 for (entry = 0; entry < nentry; entry++)
910 memset(seen, 0, data->nkeys * sizeof(Id));
912 dp = data->incoredata + data->incoreoffset[entry];
913 if (data->incoredata)
914 dp = data_read_id(dp, &oldschema);
918 fprintf(stderr, "oldschema %d\n", oldschema);
919 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
920 fprintf(stderr, "schemadata %p\n", data->schemadata);
922 /* seen: -1: old data 0: skipped >0: id + 1 */
925 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
929 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
936 if (data->attrs[entry])
937 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
944 seen[*keyp] = keyp[1] + 1;
948 /* Ideally we'd like to sort the new schema here, to ensure
949 schema equality independend of the ordering. We can't do that
950 yet. For once see below (old ids need to come before new ids).
951 An additional difficulty is that we also need to move
952 the values with the keys. */
953 schemaid = addschema(data, schema, schematacache);
955 schemaid = oldschema;
958 /* Now create data blob. We walk through the (possibly new) schema
959 and either copy over old data, or insert the new. */
960 /* XXX Here we rely on the fact that the (new) schema has the form
961 o1 o2 o3 o4 ... | n1 n2 n3 ...
962 (oX being the old keyids (possibly overwritten), and nX being
963 the new keyids). This rules out sorting the keyids in order
964 to ensure a small schema count. */
965 data->incoreoffset[entry] = newincore.len;
966 data_addid(&newincore, schemaid);
967 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
969 key = data->keys + *keyp;
973 /* Skip the data associated with this old key. */
974 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
976 ndp = data_skip(dp, TYPE_ID);
977 ndp = data_skip(ndp, TYPE_ID);
979 else if (key->storage == KEY_STORAGE_INCORE)
980 ndp = data_skip(dp, key->type);
983 if (seen[*keyp] == -1)
985 /* If this key was an old one _and_ was not overwritten with
986 a different value copy over the old value (we skipped it
989 data_addblob(&newincore, dp, ndp - dp);
992 else if (seen[*keyp])
994 /* Otherwise we have a new value. Parse it into the internal
997 unsigned int oldvincorelen = 0;
1000 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1003 oldvincorelen = xd->len;
1005 id = seen[*keyp] - 1;
1012 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1019 case TYPE_DIRNUMNUMARRAY:
1020 for (ida = data->attriddata + id; *ida; ida += 3)
1022 data_addid(xd, ida[0]);
1023 data_addid(xd, ida[1]);
1024 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1028 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1031 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1033 /* put offset/len in incore */
1034 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1035 oldvincorelen = xd->len - oldvincorelen;
1036 data_addid(&newincore, oldvincorelen);
1042 data->incoredata = newincore.buf;
1043 data->incoredatalen = newincore.len;
1044 data->incoredatafree = 0;
1046 data->vincore = newvincore.buf;
1047 data->vincorelen = newvincore.len;
1049 data->attrs = sat_free(data->attrs);
1050 data->attrdata = sat_free(data->attrdata);
1051 data->attrdatalen = 0;
1055 repodata_str2dir(Repodata *data, const char *dir, int create)
1061 while (*dir == '/' && dir[1] == '/')
1065 dire = strchrnul(dir, '/');
1066 if (data->localpool)
1067 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1069 id = strn2id(data->repo->pool, dir, dire - dir, create);
1072 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1085 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1087 return compress_buf(page, len, cpage, max);
1090 #define SOLV_ERROR_EOF 3
1092 static inline unsigned int
1098 for (i = 0; i < 4; i++)
1108 /* Try to either setup on-demand paging (using FP as backing
1109 file), or in case that doesn't work (FP not seekable) slurps in
1110 all pages and deactivates paging. */
1113 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1115 FILE *fp = data->fp;
1116 unsigned int npages;
1118 unsigned int can_seek;
1120 unsigned char buf[BLOB_PAGESIZE];
1121 if (pagesz != BLOB_PAGESIZE)
1123 /* We could handle this by slurping in everything. */
1124 fprintf (stderr, "non matching page size\n");
1128 if ((cur_file_ofs = ftell(fp)) < 0)
1132 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1134 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1136 data->num_pages = npages;
1137 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1139 /* If we can't seek on our input we have to slurp in everything. */
1141 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1142 for (i = 0; i < npages; i++)
1144 unsigned int in_len = read_u32(fp);
1145 unsigned int compressed = in_len & 1;
1146 Attrblobpage *p = data->pages + i;
1149 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1150 i, in_len, compressed ? "" : "not ");
1156 p->file_offset = cur_file_ofs;
1157 p->file_size = in_len * 2 + compressed;
1158 if (fseek(fp, in_len, SEEK_CUR) < 0)
1161 fprintf (stderr, "can't seek after we thought we can\n");
1162 /* We can't fall back to non-seeking behaviour as we already
1163 read over some data pages without storing them away. */
1166 cur_file_ofs += in_len;
1170 unsigned int out_len;
1171 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1172 p->mapped_at = i * BLOB_PAGESIZE;
1175 /* We can't seek, so suck everything in. */
1176 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1183 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1184 if (out_len != BLOB_PAGESIZE
1187 fprintf (stderr, "can't decompress\n");
1196 /* If we are here we were able to seek to all page
1197 positions, so activate paging by copying FP into our structure.
1198 We dup() the file, so that our callers can fclose() it and we
1199 still have it open. But this means that we share file positions
1200 with the input filedesc. So in case our caller reads it after us,
1201 and calls back into us we might change the file position unexpectedly
1203 int fd = dup (fileno (fp));
1206 /* Jeez! What a bloody system, we can't dup() anymore. */
1210 /* XXX we don't close this yet anywhere. */
1211 data->fp = fdopen (fd, "r");
1214 /* My God! What happened now? */