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"
31 data_read_id(unsigned char *dp, Id *idp)
43 x = (x << 7) ^ c ^ 128;
47 static unsigned char *
48 data_read_ideof(unsigned char *dp, Id *idp, int *eof)
67 x = (x << 7) ^ c ^ 128;
71 static unsigned char *
72 data_skip(unsigned char *dp, int type)
83 while ((*dp & 0x80) != 0)
87 while ((*dp & 0xc0) != 0)
94 case TYPE_DIRSTRARRAY:
97 while ((*dp & 0x80) != 0)
106 case TYPE_DIRNUMNUMARRAY:
109 while ((*dp & 0x80) != 0)
112 while ((*dp & 0x80) != 0)
115 while ((*dp & 0x80) != 0)
122 fprintf(stderr, "unknown type in data_skip\n");
127 static unsigned char *
128 data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
141 kv->str = (const char *)dp;
142 return dp + strlen(kv->str) + 1;
144 return data_read_id(dp, &kv->id);
146 return data_read_id(dp, &kv->num);
148 return data_read_ideof(dp, &kv->id, &kv->eof);
150 return data_read_id(dp, &kv->id);
151 case TYPE_DIRSTRARRAY:
152 dp = data_read_ideof(dp, &kv->id, &kv->eof);
153 kv->str = (const char *)dp;
154 return dp + strlen(kv->str) + 1;
155 case TYPE_DIRNUMNUMARRAY:
156 dp = data_read_id(dp, &kv->id);
157 dp = data_read_id(dp, &kv->num);
158 return data_read_ideof(dp, &kv->num2, &kv->eof);
164 static unsigned char *
165 forward_to_key(Repodata *data, Id key, Id schemaid, unsigned char *dp)
169 keyp = data->schemadata + data->schemata[schemaid];
170 while ((k = *keyp++) != 0)
174 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
176 dp = data_skip(dp, TYPE_ID); /* skip that offset */
177 dp = data_skip(dp, TYPE_ID); /* skip that length */
180 if (data->keys[k].storage != KEY_STORAGE_INCORE)
182 dp = data_skip(dp, data->keys[k].type);
187 #define BLOB_PAGEBITS 15
188 #define BLOB_PAGESIZE (1 << BLOB_PAGEBITS)
190 static unsigned char *
191 load_page_range(Repodata *data, unsigned int pstart, unsigned int pend)
193 /* Make sure all pages from PSTART to PEND (inclusive) are loaded,
194 and are consecutive. Return a pointer to the mapping of PSTART. */
195 unsigned char buf[BLOB_PAGESIZE];
198 /* Quick check in case all pages are there already and consecutive. */
199 for (i = pstart; i <= pend; i++)
200 if (data->pages[i].mapped_at == -1
202 && data->pages[i].mapped_at
203 != data->pages[i-1].mapped_at + BLOB_PAGESIZE))
206 return data->blob_store + data->pages[pstart].mapped_at;
208 /* Ensure that we can map the numbers of pages we need at all. */
209 if (pend - pstart + 1 > data->ncanmap)
211 unsigned int oldcan = data->ncanmap;
212 data->ncanmap = pend - pstart + 1;
213 if (data->ncanmap < 4)
215 data->mapped = sat_realloc2(data->mapped, data->ncanmap, sizeof(data->mapped[0]));
216 memset (data->mapped + oldcan, 0, (data->ncanmap - oldcan) * sizeof (data->mapped[0]));
217 data->blob_store = sat_realloc2(data->blob_store, data->ncanmap, BLOB_PAGESIZE);
219 fprintf (stderr, "PAGE: can map %d pages\n", data->ncanmap);
223 /* Now search for "cheap" space in our store. Space is cheap if it's either
224 free (very cheap) or contains pages we search for anyway. */
226 /* Setup cost array. */
227 unsigned int cost[data->ncanmap];
228 for (i = 0; i < data->ncanmap; i++)
230 unsigned int pnum = data->mapped[i];
236 Attrblobpage *p = data->pages + pnum;
237 assert (p->mapped_at != -1);
238 if (pnum >= pstart && pnum <= pend)
245 /* And search for cheapest space. */
246 unsigned int best_cost = -1;
247 unsigned int best = 0;
248 unsigned int same_cost = 0;
249 for (i = 0; i + pend - pstart < data->ncanmap; i++)
251 unsigned int c = cost[i];
253 for (j = 0; j < pend - pstart + 1; j++)
256 best_cost = c, best = i;
257 else if (c == best_cost)
259 /* A null cost won't become better. */
263 /* If all places have the same cost we would thrash on slot 0. Avoid
264 this by doing a round-robin strategy in this case. */
265 if (same_cost == data->ncanmap - pend + pstart - 1)
266 best = data->rr_counter++ % (data->ncanmap - pend + pstart);
268 /* So we want to map our pages from [best] to [best+pend-pstart].
269 Use a very simple strategy, which doesn't make the best use of
270 our resources, but works. Throw away all pages in that range
271 (even ours) then copy around ours (in case they were outside the
272 range) or read them in. */
273 for (i = best; i < best + pend - pstart + 1; i++)
275 unsigned int pnum = data->mapped[i];
277 /* If this page is exactly at the right place already,
278 no need to evict it. */
279 && pnum != pstart + i - best)
281 /* Evict this page. */
283 fprintf (stderr, "PAGE: evict page %d from %d\n", pnum, i);
287 data->pages[pnum].mapped_at = -1;
291 /* Everything is free now. Read in the pages we want. */
292 for (i = pstart; i <= pend; i++)
294 Attrblobpage *p = data->pages + i;
295 unsigned int pnum = i - pstart + best;
296 void *dest = data->blob_store + pnum * BLOB_PAGESIZE;
297 if (p->mapped_at != -1)
299 if (p->mapped_at != pnum * BLOB_PAGESIZE)
302 fprintf (stderr, "PAGECOPY: %d to %d\n", i, pnum);
304 /* Still mapped somewhere else, so just copy it from there. */
305 memcpy (dest, data->blob_store + p->mapped_at, BLOB_PAGESIZE);
306 data->mapped[p->mapped_at / BLOB_PAGESIZE] = 0;
311 unsigned int in_len = p->file_size;
312 unsigned int compressed = in_len & 1;
315 fprintf (stderr, "PAGEIN: %d to %d", i, pnum);
317 /* Not mapped, so read in this page. */
318 if (fseek(data->fp, p->file_offset, SEEK_SET) < 0)
320 perror ("mapping fseek");
323 if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1)
325 perror ("mapping fread");
330 unsigned int out_len;
331 out_len = unchecked_decompress_buf(buf, in_len,
332 dest, BLOB_PAGESIZE);
333 if (out_len != BLOB_PAGESIZE
334 && i < data->num_pages - 1)
336 fprintf (stderr, "can't decompress\n");
340 fprintf (stderr, " (expand %d to %d)", in_len, out_len);
344 fprintf (stderr, "\n");
347 p->mapped_at = pnum * BLOB_PAGESIZE;
348 data->mapped[pnum] = i + 1;
350 return data->blob_store + best * BLOB_PAGESIZE;
353 static unsigned char *
354 make_vertical_available(Repodata *data, Repokey *key, Id off, Id len)
357 if (key->type == TYPE_VOID)
359 if (off >= data->lastverticaloffset)
361 off -= data->lastverticaloffset;
362 if (off + len > data->vincorelen)
364 return data->vincore + off;
368 if (off + len > key->size)
370 /* we now have the offset, go into vertical */
371 off += data->verticaloffset[key - data->keys];
372 dp = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
374 dp += off % BLOB_PAGESIZE;
378 static inline unsigned char *
379 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
381 unsigned char *dp = *dpp;
385 if (key->storage == KEY_STORAGE_INCORE)
387 /* hmm, this is a bit expensive */
388 *dpp = data_skip(dp, key->type);
391 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
394 dp = data_read_id(dp, &off);
395 dp = data_read_id(dp, &len);
397 return make_vertical_available(data, key, off, len);
404 repodata_lookup_str(Repodata *data, Id entry, Id keyid)
411 dp = data->incoredata + data->incoreoffset[entry];
412 dp = data_read_id(dp, &schema);
413 /* make sure the schema of this solvable contains the key */
414 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
417 dp = forward_to_key(data, keyid, schema, dp);
418 key = data->keys + keyid;
419 dp = get_data(data, key, &dp);
422 if (key->type == TYPE_STR)
423 return (const char *)dp;
424 if (key->type != TYPE_ID)
426 /* id type, must either use global or local string store*/
427 dp = data_read_id(dp, &id);
429 return data->spool.stringspace + data->spool.strings[id];
430 return id2str(data->repo->pool, id);
434 repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned *value)
443 dp = data->incoredata + data->incoreoffset[entry];
444 dp = data_read_id(dp, &schema);
445 /* make sure the schema of this solvable contains the key */
446 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
449 dp = forward_to_key(data, keyid, schema, dp);
450 key = data->keys + keyid;
451 dp = get_data(data, key, &dp);
454 if (key->type == TYPE_NUM
455 || key->type == TYPE_U32
456 || key->type == TYPE_CONSTANT)
458 dp = data_fetch(dp, &kv, key);
466 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
470 Id k, keyid, *kp, *keyp;
471 unsigned char *dp, *ddp;
476 dp = data->incoredata + data->incoreoffset[entry];
477 dp = data_read_id(dp, &schema);
478 keyp = data->schemadata + data->schemata[schema];
481 /* search in a specific key */
482 for (kp = keyp; (k = *kp++) != 0; )
483 if (data->keys[k].name == keyname)
487 dp = forward_to_key(data, k, schema, dp);
493 while ((keyid = *keyp++) != 0)
496 key = data->keys + keyid;
497 ddp = get_data(data, key, &dp);
500 ddp = data_fetch(ddp, &kv, key);
503 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
505 while (!kv.eof && !stop);
506 if (onekey || stop > SEARCH_NEXT_KEY)
512 /* extend repodata so that it includes solvables p */
514 repodata_extend(Repodata *data, Id p)
516 if (data->start == data->end)
517 data->start = data->end = p;
520 int old = data->end - data->start;
521 int new = p - data->end + 1;
524 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
525 memset(data->attrs + old, 0, new * sizeof(Id *));
527 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
528 memset(data->incoreoffset + old, 0, new * sizeof(Id));
533 int old = data->end - data->start;
534 int new = data->start - p;
537 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
538 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
539 memset(data->attrs, 0, new * sizeof(Id *));
541 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
542 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
543 memset(data->incoreoffset, 0, new * sizeof(Id));
549 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
554 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
556 if (data->attrs[entry])
558 for (pp = data->attrs[entry]; *pp; pp += 2)
559 /* Determine equality based on the name only, allows us to change
560 type (when overwrite is set), and makes TYPE_CONSTANT work. */
561 if (data->keys[*pp].name == data->keys[keyid].name)
572 i = pp - data->attrs[entry];
574 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
575 pp = data->attrs[entry] + i;
582 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
586 /* find key in keys */
587 for (keyid = 1; keyid < data->nkeys; keyid++)
588 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
590 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
594 if (keyid == data->nkeys)
596 /* allocate new key */
597 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
598 data->keys[data->nkeys++] = *key;
599 if (data->verticaloffset)
601 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
602 data->verticaloffset[data->nkeys - 1] = 0;
605 repodata_insert_keyid(data, entry, keyid, val, 1);
609 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
615 key.storage = KEY_STORAGE_INCORE;
616 repodata_set(data, entry, &key, id);
620 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
626 key.storage = KEY_STORAGE_INCORE;
627 repodata_set(data, entry, &key, num);
631 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
636 id = stringpool_str2id(&data->spool, str, 1);
638 id = str2id(data->repo->pool, str, 1);
642 key.storage = KEY_STORAGE_INCORE;
643 repodata_set(data, entry, &key, id);
647 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
651 key.type = TYPE_CONSTANT;
653 key.storage = KEY_STORAGE_INCORE;
654 repodata_set(data, entry, &key, 0);
658 repodata_set_void(Repodata *data, Id entry, Id keyname)
662 key.type = TYPE_VOID;
664 key.storage = KEY_STORAGE_INCORE;
665 repodata_set(data, entry, &key, 0);
669 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
678 key.storage = KEY_STORAGE_INCORE;
679 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
680 memcpy(data->attrdata + data->attrdatalen, str, l);
681 repodata_set(data, entry, &key, data->attrdatalen);
682 data->attrdatalen += l;
686 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
692 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
694 if (data->attrs && data->attrs[entry])
696 for (pp = data->attrs[entry]; *pp; pp += 2)
697 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
702 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
704 if (ida + 1 == data->attriddata + data->attriddatalen)
706 /* this was the last entry, just append it */
707 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
708 data->attriddatalen--; /* overwrite terminating 0 */
712 /* too bad. move to back. */
713 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
714 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
715 pp[1] = data->attriddatalen;
716 data->attriddatalen += oldsize;
718 data->attriddata[data->attriddatalen++] = dir;
719 data->attriddata[data->attriddatalen++] = num;
720 data->attriddata[data->attriddatalen++] = num2;
721 data->attriddata[data->attriddatalen++] = 0;
726 key.type = TYPE_DIRNUMNUMARRAY;
728 key.storage = KEY_STORAGE_INCORE;
729 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
730 repodata_set(data, entry, &key, data->attriddatalen);
731 data->attriddata[data->attriddatalen++] = dir;
732 data->attriddata[data->attriddatalen++] = num;
733 data->attriddata[data->attriddatalen++] = num2;
734 data->attriddata[data->attriddatalen++] = 0;
738 repodata_merge_attrs (Repodata *data, Id dest, Id src)
741 for (keyp = data->attrs[src]; *keyp; keyp += 2)
742 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
745 /*********************************/
747 /* unify with repo_write! */
749 #define EXTDATA_BLOCK 1023
750 #define SCHEMATA_BLOCK 31
751 #define SCHEMATADATA_BLOCK 255
759 data_addid(struct extdata *xd, Id x)
762 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
763 dp = xd->buf + xd->len;
768 *dp++ = (x >> 28) | 128;
770 *dp++ = (x >> 21) | 128;
771 *dp++ = (x >> 14) | 128;
774 *dp++ = (x >> 7) | 128;
776 xd->len = dp - xd->buf;
780 data_addideof(struct extdata *xd, Id x, int eof)
783 x = (x & 63) | ((x & ~63) << 1);
784 data_addid(xd, (eof ? x: x | 64));
788 data_addblob(struct extdata *xd, unsigned char *blob, int len)
790 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
791 memcpy(xd->buf + xd->len, blob, len);
795 /*********************************/
798 addschema_prepare(Repodata *data, Id *schematacache)
803 memset(schematacache, 0, 256 * sizeof(Id));
804 for (i = 0; i < data->nschemata; i++)
806 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
809 schematacache[h] = i + 1;
811 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
812 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
816 addschema(Repodata *data, Id *schema, Id *schematacache)
821 for (sp = schema, len = 0, h = 0; *sp; len++)
826 cid = schematacache[h];
830 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
833 for (cid = 0; cid < data->nschemata; cid++)
834 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
837 /* a new one. make room. */
838 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
839 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
841 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
842 data->schemata[data->nschemata] = data->schemadatalen;
843 data->schemadatalen += len;
844 schematacache[h] = data->nschemata + 1;
846 fprintf(stderr, "addschema: new schema\n");
848 return data->nschemata++;
853 repodata_internalize(Repodata *data)
856 Id id, entry, nentry, *ida;
857 Id schematacache[256];
858 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
859 unsigned char *dp, *ndp;
860 int newschema, oldcount;
861 struct extdata newincore;
862 struct extdata newvincore;
867 newvincore.buf = data->vincore;
868 newvincore.len = data->vincorelen;
870 schema = sat_malloc2(data->nkeys, sizeof(Id));
871 seen = sat_malloc2(data->nkeys, sizeof(Id));
873 /* Merge the data already existing (in data->schemata, ->incoredata and
874 friends) with the new attributes in data->attrs[]. */
875 nentry = data->end - data->start;
876 addschema_prepare(data, schematacache);
877 memset(&newincore, 0, sizeof(newincore));
878 for (entry = 0; entry < nentry; entry++)
880 memset(seen, 0, data->nkeys * sizeof(Id));
882 dp = data->incoredata + data->incoreoffset[entry];
883 if (data->incoredata)
884 dp = data_read_id(dp, &oldschema);
888 fprintf(stderr, "oldschema %d\n", oldschema);
889 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
890 fprintf(stderr, "schemadata %p\n", data->schemadata);
892 /* seen: -1: old data 0: skipped >0: id + 1 */
895 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
899 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
906 if (data->attrs[entry])
907 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
914 seen[*keyp] = keyp[1] + 1;
918 /* Ideally we'd like to sort the new schema here, to ensure
919 schema equality independend of the ordering. We can't do that
920 yet. For once see below (old ids need to come before new ids).
921 An additional difficulty is that we also need to move
922 the values with the keys. */
923 schemaid = addschema(data, schema, schematacache);
925 schemaid = oldschema;
928 /* Now create data blob. We walk through the (possibly new) schema
929 and either copy over old data, or insert the new. */
930 /* XXX Here we rely on the fact that the (new) schema has the form
931 o1 o2 o3 o4 ... | n1 n2 n3 ...
932 (oX being the old keyids (possibly overwritten), and nX being
933 the new keyids). This rules out sorting the keyids in order
934 to ensure a small schema count. */
935 data->incoreoffset[entry] = newincore.len;
936 data_addid(&newincore, schemaid);
937 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
939 key = data->keys + *keyp;
943 /* Skip the data associated with this old key. */
944 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
946 ndp = data_skip(dp, TYPE_ID);
947 ndp = data_skip(ndp, TYPE_ID);
949 else if (key->storage == KEY_STORAGE_INCORE)
950 ndp = data_skip(dp, key->type);
953 if (seen[*keyp] == -1)
955 /* If this key was an old one _and_ was not overwritten with
956 a different value copy over the old value (we skipped it
959 data_addblob(&newincore, dp, ndp - dp);
962 else if (seen[*keyp])
964 /* Otherwise we have a new value. Parse it into the internal
967 unsigned int oldvincorelen = 0;
970 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
973 oldvincorelen = xd->len;
975 id = seen[*keyp] - 1;
982 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
989 case TYPE_DIRNUMNUMARRAY:
990 for (ida = data->attriddata + id; *ida; ida += 3)
992 data_addid(xd, ida[0]);
993 data_addid(xd, ida[1]);
994 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
998 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1001 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1003 /* put offset/len in incore */
1004 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1005 oldvincorelen = xd->len - oldvincorelen;
1006 data_addid(&newincore, oldvincorelen);
1012 data->incoredata = newincore.buf;
1013 data->incoredatalen = newincore.len;
1014 data->incoredatafree = 0;
1016 data->vincore = newvincore.buf;
1017 data->vincorelen = newvincore.len;
1019 data->attrs = sat_free(data->attrs);
1020 data->attrdata = sat_free(data->attrdata);
1021 data->attrdatalen = 0;
1025 repodata_str2dir(Repodata *data, const char *dir, int create)
1031 while (*dir == '/' && dir[1] == '/')
1035 dire = strchrnul(dir, '/');
1036 if (data->localpool)
1037 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1039 id = strn2id(data->repo->pool, dir, dire - dir, create);
1042 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1055 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1057 return compress_buf(page, len, cpage, max);
1060 #define SOLV_ERROR_EOF 3
1062 static inline unsigned int
1068 for (i = 0; i < 4; i++)
1078 /* Try to either setup on-demand paging (using FP as backing
1079 file), or in case that doesn't work (FP not seekable) slurps in
1080 all pages and deactivates paging. */
1083 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1085 FILE *fp = data->fp;
1086 unsigned int npages;
1088 unsigned int can_seek;
1090 unsigned char buf[BLOB_PAGESIZE];
1091 if (pagesz != BLOB_PAGESIZE)
1093 /* We could handle this by slurping in everything. */
1094 fprintf (stderr, "non matching page size\n");
1098 if ((cur_file_ofs = ftell(fp)) < 0)
1102 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1104 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1106 data->num_pages = npages;
1107 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1109 /* If we can't seek on our input we have to slurp in everything. */
1111 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1112 for (i = 0; i < npages; i++)
1114 unsigned int in_len = read_u32(fp);
1115 unsigned int compressed = in_len & 1;
1116 Attrblobpage *p = data->pages + i;
1119 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1120 i, in_len, compressed ? "" : "not ");
1126 p->file_offset = cur_file_ofs;
1127 p->file_size = in_len * 2 + compressed;
1128 if (fseek(fp, in_len, SEEK_CUR) < 0)
1131 fprintf (stderr, "can't seek after we thought we can\n");
1132 /* We can't fall back to non-seeking behaviour as we already
1133 read over some data pages without storing them away. */
1136 cur_file_ofs += in_len;
1140 unsigned int out_len;
1141 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1142 p->mapped_at = i * BLOB_PAGESIZE;
1145 /* We can't seek, so suck everything in. */
1146 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1153 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1154 if (out_len != BLOB_PAGESIZE
1157 fprintf (stderr, "can't decompress\n");
1166 /* If we are here we were able to seek to all page
1167 positions, so activate paging by copying FP into our structure.
1168 We dup() the file, so that our callers can fclose() it and we
1169 still have it open. But this means that we share file positions
1170 with the input filedesc. So in case our caller reads it after us,
1171 and calls back into us we might change the file position unexpectedly
1173 int fd = dup (fileno (fp));
1176 /* Jeez! What a bloody system, we can't dup() anymore. */
1180 /* XXX we don't close this yet anywhere. */
1181 data->fp = fdopen (fd, "r");
1184 /* My God! What happened now? */