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 if (data->entryschemau8)
412 schema = data->entryschemau8[entry];
414 schema = data->entryschema[entry];
415 /* make sure the schema of this solvable contains the key */
416 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
419 dp = forward_to_key(data, keyid, schema, data->incoredata + data->incoreoffset[entry]);
420 key = data->keys + keyid;
421 dp = get_data(data, key, &dp);
424 if (key->type == TYPE_STR)
425 return (const char *)dp;
426 if (key->type != TYPE_ID)
428 /* id type, must either use global or local string strore*/
429 dp = data_read_id(dp, &id);
431 return data->spool.stringspace + data->spool.strings[id];
432 return id2str(data->repo->pool, id);
436 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
440 Id k, keyid, *kp, *keyp;
441 unsigned char *dp, *ddp;
446 if (data->entryschemau8)
447 schema = data->entryschemau8[entry];
449 schema = data->entryschema[entry];
450 keyp = data->schemadata + data->schemata[schema];
451 dp = data->incoredata + data->incoreoffset[entry];
454 /* search in a specific key */
455 for (kp = keyp; (k = *kp++) != 0; )
456 if (data->keys[k].name == keyname)
460 dp = forward_to_key(data, k, schema, dp);
466 while ((keyid = *keyp++) != 0)
469 key = data->keys + keyid;
470 ddp = get_data(data, key, &dp);
473 ddp = data_fetch(ddp, &kv, key);
476 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
478 while (!kv.eof && !stop);
479 if (onekey || stop > SEARCH_NEXT_KEY)
485 /* extend repodata so that it includes solvables p */
487 repodata_extend(Repodata *data, Id p)
489 if (data->start == data->end)
490 data->start = data->end = p;
493 int old = data->end - data->start;
494 int new = p - data->end + 1;
495 if (data->entryschemau8)
497 data->entryschemau8 = sat_realloc(data->entryschemau8, old + new);
498 memset(data->entryschemau8 + old, 0, new);
500 if (data->entryschema)
502 data->entryschema = sat_realloc2(data->entryschema, old + new, sizeof(Id));
503 memset(data->entryschema + old, 0, new * sizeof(Id));
507 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
508 memset(data->attrs + old, 0, new * sizeof(Id *));
510 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
511 memset(data->incoreoffset + old, 0, new * sizeof(Id));
516 int old = data->end - data->start;
517 int new = data->start - p;
518 if (data->entryschemau8)
520 data->entryschemau8 = sat_realloc(data->entryschemau8, old + new);
521 memmove(data->entryschemau8 + new, data->entryschemau8, old);
522 memset(data->entryschemau8, 0, new);
524 if (data->entryschema)
526 data->entryschema = sat_realloc2(data->entryschema, old + new, sizeof(Id));
527 memmove(data->entryschema + new, data->entryschema, old * sizeof(Id));
528 memset(data->entryschema, 0, new * sizeof(Id));
532 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
533 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
534 memset(data->attrs, 0, new * sizeof(Id *));
536 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
537 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
538 memset(data->incoreoffset, 0, new * sizeof(Id));
544 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
549 /* find key in keys */
550 for (keyid = 1; keyid < data->nkeys; keyid++)
551 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
553 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
557 if (keyid == data->nkeys)
559 /* allocate new key */
560 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
561 data->keys[data->nkeys++] = *key;
562 if (data->verticaloffset)
564 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
565 data->verticaloffset[data->nkeys - 1] = 0;
568 key = data->keys + keyid;
570 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
572 if (data->attrs[entry])
574 for (pp = data->attrs[entry]; *pp; pp += 2)
582 i = pp - data->attrs[entry];
584 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
585 pp = data->attrs[entry] + i;
592 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
598 key.storage = KEY_STORAGE_INCORE;
599 repodata_set(data, entry, &key, id);
603 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
609 key.storage = KEY_STORAGE_INCORE;
610 repodata_set(data, entry, &key, num);
614 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
619 id = stringpool_str2id(&data->spool, str, 1);
621 id = str2id(data->repo->pool, str, 1);
625 key.storage = KEY_STORAGE_INCORE;
626 repodata_set(data, entry, &key, id);
630 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
634 key.type = TYPE_CONSTANT;
636 key.storage = KEY_STORAGE_INCORE;
637 repodata_set(data, entry, &key, 0);
641 repodata_set_void(Repodata *data, Id entry, Id keyname)
645 key.type = TYPE_VOID;
647 key.storage = KEY_STORAGE_INCORE;
648 repodata_set(data, entry, &key, 0);
652 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
661 key.storage = KEY_STORAGE_INCORE;
662 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
663 memcpy(data->attrdata + data->attrdatalen, str, l);
664 repodata_set(data, entry, &key, data->attrdatalen);
665 data->attrdatalen += l;
669 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
675 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
677 if (data->attrs[entry])
679 for (pp = data->attrs[entry]; *pp; pp += 2)
680 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
685 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
687 if (ida + 1 == data->attriddata + data->attriddatalen)
689 /* this was the last entry, just append it */
690 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
691 data->attriddatalen--; /* overwrite terminating 0 */
695 /* too bad. move to back. */
696 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
697 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
698 pp[1] = data->attriddatalen;
699 data->attriddatalen += oldsize;
701 data->attriddata[data->attriddatalen++] = dir;
702 data->attriddata[data->attriddatalen++] = num;
703 data->attriddata[data->attriddatalen++] = num2;
704 data->attriddata[data->attriddatalen++] = 0;
709 key.type = TYPE_DIRNUMNUMARRAY;
711 key.storage = KEY_STORAGE_INCORE;
712 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
713 repodata_set(data, entry, &key, data->attriddatalen);
714 data->attriddata[data->attriddatalen++] = dir;
715 data->attriddata[data->attriddatalen++] = num;
716 data->attriddata[data->attriddatalen++] = num2;
717 data->attriddata[data->attriddatalen++] = 0;
720 /*********************************/
722 /* unify with repo_write! */
724 #define EXTDATA_BLOCK 1023
725 #define SCHEMATA_BLOCK 31
726 #define SCHEMATADATA_BLOCK 255
734 data_addid(struct extdata *xd, Id x)
737 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
738 dp = xd->buf + xd->len;
743 *dp++ = (x >> 28) | 128;
745 *dp++ = (x >> 21) | 128;
746 *dp++ = (x >> 14) | 128;
749 *dp++ = (x >> 7) | 128;
751 xd->len = dp - xd->buf;
755 data_addideof(struct extdata *xd, Id x, int eof)
758 x = (x & 63) | ((x & ~63) << 1);
759 data_addid(xd, (eof ? x: x | 64));
763 data_addblob(struct extdata *xd, unsigned char *blob, int len)
765 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
766 memcpy(xd->buf + xd->len, blob, len);
770 /*********************************/
773 addschema_prepare(Repodata *data, Id *schematacache)
778 memset(schematacache, 0, 256 * sizeof(Id));
779 for (i = 0; i < data->nschemata; i++)
781 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
784 schematacache[h] = i + 1;
786 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
787 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
791 addschema(Repodata *data, Id *schema, Id *schematacache)
796 for (sp = schema, len = 0, h = 0; *sp; len++)
801 cid = schematacache[h];
805 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
808 for (cid = 0; cid < data->nschemata; cid++)
809 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
812 /* a new one. make room. */
813 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
814 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
816 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
817 data->schemata[data->nschemata] = data->schemadatalen;
818 data->schemadatalen += len;
819 schematacache[h] = data->nschemata + 1;
821 fprintf(stderr, "addschema: new schema\n");
823 return data->nschemata++;
828 repodata_internalize(Repodata *data)
832 Id id, entry, nentry, *ida;
833 Id schematacache[256];
834 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
835 unsigned char *dp, *ndp;
836 int newschema, oldcount;
837 struct extdata newincore;
838 struct extdata newvincore;
843 newvincore.buf = data->vincore;
844 newvincore.len = data->vincorelen;
846 schema = sat_malloc2(data->nkeys, sizeof(Id));
847 seen = sat_malloc2(data->nkeys, sizeof(Id));
849 /* Merge the data already existing (in data->schemata, ->incoredata and
850 friends) with the new attributes in data->attrs[]. */
851 nentry = data->end - data->start;
852 addschema_prepare(data, schematacache);
853 memset(&newincore, 0, sizeof(newincore));
854 for (entry = 0; entry < nentry; entry++)
856 memset(seen, 0, data->nkeys * sizeof(Id));
858 if (data->entryschemau8)
859 oldschema = data->entryschemau8[entry];
861 oldschema = data->entryschema[entry];
863 fprintf(stderr, "oldschema %d\n", oldschema);
864 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
865 fprintf(stderr, "schemadata %p\n", data->schemadata);
867 /* seen: -1: old data 0: skipped >0: id + 1 */
870 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
874 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
881 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
888 seen[*keyp] = keyp[1] + 1;
893 /* Ideally we'd like to sort the new schema here, to ensure
894 schema equality independend of the ordering. We can't do that
895 yet. For once see below (old ids need to come before new ids).
896 An additional difficulty is that we also need to move
897 the values with the keys. */
898 schemaid = addschema(data, schema, schematacache);
899 if (schemaid > 255 && data->entryschemau8)
901 data->entryschema = sat_malloc2(nentry, sizeof(Id));
902 for (i = 0; i < nentry; i++)
903 data->entryschema[i] = data->entryschemau8[i];
904 data->entryschemau8 = sat_free(data->entryschemau8);
906 if (data->entryschemau8)
907 data->entryschemau8[entry] = schemaid;
909 data->entryschema[entry] = schemaid;
912 schemaid = oldschema;
915 /* Now create data blob. We walk through the (possibly new) schema
916 and either copy over old data, or insert the new. */
917 /* XXX Here we rely on the fact that the (new) schema has the form
918 o1 o2 o3 o4 ... | n1 n2 n3 ...
919 (oX being the old keyids (possibly overwritten), and nX being
920 the new keyids). This rules out sorting the keyids in order
921 to ensure a small schema count. */
922 dp = data->incoredata + data->incoreoffset[entry];
923 data->incoreoffset[entry] = newincore.len;
924 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
926 key = data->keys + *keyp;
930 /* Skip the data associated with this old key. */
931 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
933 ndp = data_skip(dp, TYPE_ID);
934 ndp = data_skip(ndp, TYPE_ID);
936 else if (key->storage == KEY_STORAGE_INCORE)
937 ndp = data_skip(dp, key->type);
940 if (seen[*keyp] == -1)
942 /* If this key was an old one _and_ was not overwritten with
943 a different value copy over the old value (we skipped it
946 data_addblob(&newincore, dp, ndp - dp);
949 else if (seen[*keyp])
951 /* Otherwise we have a new value. Parse it into the internal
954 unsigned int oldvincorelen = 0;
957 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
960 oldvincorelen = xd->len;
962 id = seen[*keyp] - 1;
969 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
976 case TYPE_DIRNUMNUMARRAY:
977 for (ida = data->attriddata + id; *ida; ida += 3)
979 data_addid(xd, ida[0]);
980 data_addid(xd, ida[1]);
981 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
985 fprintf(stderr, "don't know how to handle type %d\n", key->type);
988 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
990 /* put offset/len in incore */
991 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
992 oldvincorelen = xd->len - oldvincorelen;
993 data_addid(&newincore, oldvincorelen);
999 data->incoredata = newincore.buf;
1000 data->incoredatalen = newincore.len;
1001 data->incoredatafree = 0;
1003 data->vincore = newvincore.buf;
1004 data->vincorelen = newvincore.len;
1006 data->attrs = sat_free(data->attrs);
1007 data->attrdata = sat_free(data->attrdata);
1008 data->attrdatalen = 0;
1012 repodata_str2dir(Repodata *data, const char *dir, int create)
1018 while (*dir == '/' && dir[1] == '/')
1022 dire = strchrnul(dir, '/');
1023 if (data->localpool)
1024 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1026 id = strn2id(data->repo->pool, dir, dire - dir, create);
1029 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1042 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1044 return compress_buf(page, len, cpage, max);
1047 #define SOLV_ERROR_EOF 3
1049 static inline unsigned int
1055 for (i = 0; i < 4; i++)
1065 /* Try to either setup on-demand paging (using FP as backing
1066 file), or in case that doesn't work (FP not seekable) slurps in
1067 all pages and deactivates paging. */
1070 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1072 FILE *fp = data->fp;
1073 unsigned int npages;
1075 unsigned int can_seek;
1077 unsigned char buf[BLOB_PAGESIZE];
1078 if (pagesz != BLOB_PAGESIZE)
1080 /* We could handle this by slurping in everything. */
1081 fprintf (stderr, "non matching page size\n");
1085 if ((cur_file_ofs = ftell(fp)) < 0)
1089 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1091 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1093 data->num_pages = npages;
1094 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1096 /* If we can't seek on our input we have to slurp in everything. */
1098 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1099 for (i = 0; i < npages; i++)
1101 unsigned int in_len = read_u32(fp);
1102 unsigned int compressed = in_len & 1;
1103 Attrblobpage *p = data->pages + i;
1106 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1107 i, in_len, compressed ? "" : "not ");
1113 p->file_offset = cur_file_ofs;
1114 p->file_size = in_len * 2 + compressed;
1115 if (fseek(fp, in_len, SEEK_CUR) < 0)
1118 fprintf (stderr, "can't seek after we thought we can\n");
1119 /* We can't fall back to non-seeking behaviour as we already
1120 read over some data pages without storing them away. */
1123 cur_file_ofs += in_len;
1127 unsigned int out_len;
1128 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1129 p->mapped_at = i * BLOB_PAGESIZE;
1132 /* We can't seek, so suck everything in. */
1133 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1140 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1141 if (out_len != BLOB_PAGESIZE
1144 fprintf (stderr, "can't decompress\n");
1153 /* If we are here we were able to seek to all page
1154 positions, so activate paging by copying FP into our structure.
1155 We dup() the file, so that our callers can fclose() it and we
1156 still have it open. But this means that we share file positions
1157 with the input filedesc. So in case our caller reads it after us,
1158 and calls back into us we might change the file position unexpectedly
1160 int fd = dup (fileno (fp));
1163 /* Jeez! What a bloody system, we can't dup() anymore. */
1167 /* XXX we don't close this yet anywhere. */
1168 data->fp = fdopen (fd, "r");
1171 /* My God! What happened now? */