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 strore*/
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)
442 dp = data->incoredata + data->incoreoffset[entry];
443 dp = data_read_id(dp, &schema);
444 /* make sure the schema of this solvable contains the key */
445 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
448 dp = forward_to_key(data, keyid, schema, dp);
449 key = data->keys + keyid;
450 dp = get_data(data, key, &dp);
453 if (key->type == TYPE_NUM || key->type == TYPE_U32)
455 dp = data_fetch(dp, &kv, key);
462 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
466 Id k, keyid, *kp, *keyp;
467 unsigned char *dp, *ddp;
472 dp = data->incoredata + data->incoreoffset[entry];
473 dp = data_read_id(dp, &schema);
474 keyp = data->schemadata + data->schemata[schema];
477 /* search in a specific key */
478 for (kp = keyp; (k = *kp++) != 0; )
479 if (data->keys[k].name == keyname)
483 dp = forward_to_key(data, k, schema, dp);
489 while ((keyid = *keyp++) != 0)
492 key = data->keys + keyid;
493 ddp = get_data(data, key, &dp);
496 ddp = data_fetch(ddp, &kv, key);
499 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
501 while (!kv.eof && !stop);
502 if (onekey || stop > SEARCH_NEXT_KEY)
508 /* extend repodata so that it includes solvables p */
510 repodata_extend(Repodata *data, Id p)
512 if (data->start == data->end)
513 data->start = data->end = p;
516 int old = data->end - data->start;
517 int new = p - data->end + 1;
520 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
521 memset(data->attrs + old, 0, new * sizeof(Id *));
523 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
524 memset(data->incoreoffset + old, 0, new * sizeof(Id));
529 int old = data->end - data->start;
530 int new = data->start - p;
533 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
534 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
535 memset(data->attrs, 0, new * sizeof(Id *));
537 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
538 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
539 memset(data->incoreoffset, 0, new * sizeof(Id));
545 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
550 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
552 if (data->attrs[entry])
554 for (pp = data->attrs[entry]; *pp; pp += 2)
563 i = pp - data->attrs[entry];
565 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
566 pp = data->attrs[entry] + i;
573 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
577 /* find key in keys */
578 for (keyid = 1; keyid < data->nkeys; keyid++)
579 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
581 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
585 if (keyid == data->nkeys)
587 /* allocate new key */
588 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
589 data->keys[data->nkeys++] = *key;
590 if (data->verticaloffset)
592 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
593 data->verticaloffset[data->nkeys - 1] = 0;
596 repodata_insert_keyid(data, entry, keyid, val, 1);
600 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
606 key.storage = KEY_STORAGE_INCORE;
607 repodata_set(data, entry, &key, id);
611 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
617 key.storage = KEY_STORAGE_INCORE;
618 repodata_set(data, entry, &key, num);
622 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
627 id = stringpool_str2id(&data->spool, str, 1);
629 id = str2id(data->repo->pool, str, 1);
633 key.storage = KEY_STORAGE_INCORE;
634 repodata_set(data, entry, &key, id);
638 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
642 key.type = TYPE_CONSTANT;
644 key.storage = KEY_STORAGE_INCORE;
645 repodata_set(data, entry, &key, 0);
649 repodata_set_void(Repodata *data, Id entry, Id keyname)
653 key.type = TYPE_VOID;
655 key.storage = KEY_STORAGE_INCORE;
656 repodata_set(data, entry, &key, 0);
660 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
669 key.storage = KEY_STORAGE_INCORE;
670 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
671 memcpy(data->attrdata + data->attrdatalen, str, l);
672 repodata_set(data, entry, &key, data->attrdatalen);
673 data->attrdatalen += l;
677 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
683 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
685 if (data->attrs && data->attrs[entry])
687 for (pp = data->attrs[entry]; *pp; pp += 2)
688 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
693 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
695 if (ida + 1 == data->attriddata + data->attriddatalen)
697 /* this was the last entry, just append it */
698 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
699 data->attriddatalen--; /* overwrite terminating 0 */
703 /* too bad. move to back. */
704 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
705 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
706 pp[1] = data->attriddatalen;
707 data->attriddatalen += oldsize;
709 data->attriddata[data->attriddatalen++] = dir;
710 data->attriddata[data->attriddatalen++] = num;
711 data->attriddata[data->attriddatalen++] = num2;
712 data->attriddata[data->attriddatalen++] = 0;
717 key.type = TYPE_DIRNUMNUMARRAY;
719 key.storage = KEY_STORAGE_INCORE;
720 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
721 repodata_set(data, entry, &key, data->attriddatalen);
722 data->attriddata[data->attriddatalen++] = dir;
723 data->attriddata[data->attriddatalen++] = num;
724 data->attriddata[data->attriddatalen++] = num2;
725 data->attriddata[data->attriddatalen++] = 0;
729 repodata_merge_attrs (Repodata *data, Id dest, Id src)
732 for (keyp = data->attrs[src]; *keyp; keyp += 2)
733 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
736 /*********************************/
738 /* unify with repo_write! */
740 #define EXTDATA_BLOCK 1023
741 #define SCHEMATA_BLOCK 31
742 #define SCHEMATADATA_BLOCK 255
750 data_addid(struct extdata *xd, Id x)
753 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
754 dp = xd->buf + xd->len;
759 *dp++ = (x >> 28) | 128;
761 *dp++ = (x >> 21) | 128;
762 *dp++ = (x >> 14) | 128;
765 *dp++ = (x >> 7) | 128;
767 xd->len = dp - xd->buf;
771 data_addideof(struct extdata *xd, Id x, int eof)
774 x = (x & 63) | ((x & ~63) << 1);
775 data_addid(xd, (eof ? x: x | 64));
779 data_addblob(struct extdata *xd, unsigned char *blob, int len)
781 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
782 memcpy(xd->buf + xd->len, blob, len);
786 /*********************************/
789 addschema_prepare(Repodata *data, Id *schematacache)
794 memset(schematacache, 0, 256 * sizeof(Id));
795 for (i = 0; i < data->nschemata; i++)
797 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
800 schematacache[h] = i + 1;
802 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
803 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
807 addschema(Repodata *data, Id *schema, Id *schematacache)
812 for (sp = schema, len = 0, h = 0; *sp; len++)
817 cid = schematacache[h];
821 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
824 for (cid = 0; cid < data->nschemata; cid++)
825 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
828 /* a new one. make room. */
829 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
830 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
832 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
833 data->schemata[data->nschemata] = data->schemadatalen;
834 data->schemadatalen += len;
835 schematacache[h] = data->nschemata + 1;
837 fprintf(stderr, "addschema: new schema\n");
839 return data->nschemata++;
844 repodata_internalize(Repodata *data)
847 Id id, entry, nentry, *ida;
848 Id schematacache[256];
849 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
850 unsigned char *dp, *ndp;
851 int newschema, oldcount;
852 struct extdata newincore;
853 struct extdata newvincore;
858 newvincore.buf = data->vincore;
859 newvincore.len = data->vincorelen;
861 schema = sat_malloc2(data->nkeys, sizeof(Id));
862 seen = sat_malloc2(data->nkeys, sizeof(Id));
864 /* Merge the data already existing (in data->schemata, ->incoredata and
865 friends) with the new attributes in data->attrs[]. */
866 nentry = data->end - data->start;
867 addschema_prepare(data, schematacache);
868 memset(&newincore, 0, sizeof(newincore));
869 for (entry = 0; entry < nentry; entry++)
871 memset(seen, 0, data->nkeys * sizeof(Id));
873 dp = data->incoredata + data->incoreoffset[entry];
874 if (data->incoredata)
875 dp = data_read_id(dp, &oldschema);
879 fprintf(stderr, "oldschema %d\n", oldschema);
880 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
881 fprintf(stderr, "schemadata %p\n", data->schemadata);
883 /* seen: -1: old data 0: skipped >0: id + 1 */
886 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
890 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
897 if (data->attrs[entry])
898 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
905 seen[*keyp] = keyp[1] + 1;
909 /* Ideally we'd like to sort the new schema here, to ensure
910 schema equality independend of the ordering. We can't do that
911 yet. For once see below (old ids need to come before new ids).
912 An additional difficulty is that we also need to move
913 the values with the keys. */
914 schemaid = addschema(data, schema, schematacache);
916 schemaid = oldschema;
919 /* Now create data blob. We walk through the (possibly new) schema
920 and either copy over old data, or insert the new. */
921 /* XXX Here we rely on the fact that the (new) schema has the form
922 o1 o2 o3 o4 ... | n1 n2 n3 ...
923 (oX being the old keyids (possibly overwritten), and nX being
924 the new keyids). This rules out sorting the keyids in order
925 to ensure a small schema count. */
926 data->incoreoffset[entry] = newincore.len;
927 data_addid(&newincore, schemaid);
928 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
930 key = data->keys + *keyp;
934 /* Skip the data associated with this old key. */
935 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
937 ndp = data_skip(dp, TYPE_ID);
938 ndp = data_skip(ndp, TYPE_ID);
940 else if (key->storage == KEY_STORAGE_INCORE)
941 ndp = data_skip(dp, key->type);
944 if (seen[*keyp] == -1)
946 /* If this key was an old one _and_ was not overwritten with
947 a different value copy over the old value (we skipped it
950 data_addblob(&newincore, dp, ndp - dp);
953 else if (seen[*keyp])
955 /* Otherwise we have a new value. Parse it into the internal
958 unsigned int oldvincorelen = 0;
961 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
964 oldvincorelen = xd->len;
966 id = seen[*keyp] - 1;
973 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
980 case TYPE_DIRNUMNUMARRAY:
981 for (ida = data->attriddata + id; *ida; ida += 3)
983 data_addid(xd, ida[0]);
984 data_addid(xd, ida[1]);
985 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
989 fprintf(stderr, "don't know how to handle type %d\n", key->type);
992 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
994 /* put offset/len in incore */
995 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
996 oldvincorelen = xd->len - oldvincorelen;
997 data_addid(&newincore, oldvincorelen);
1003 data->incoredata = newincore.buf;
1004 data->incoredatalen = newincore.len;
1005 data->incoredatafree = 0;
1007 data->vincore = newvincore.buf;
1008 data->vincorelen = newvincore.len;
1010 data->attrs = sat_free(data->attrs);
1011 data->attrdata = sat_free(data->attrdata);
1012 data->attrdatalen = 0;
1016 repodata_str2dir(Repodata *data, const char *dir, int create)
1022 while (*dir == '/' && dir[1] == '/')
1026 dire = strchrnul(dir, '/');
1027 if (data->localpool)
1028 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1030 id = strn2id(data->repo->pool, dir, dire - dir, create);
1033 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1046 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1048 return compress_buf(page, len, cpage, max);
1051 #define SOLV_ERROR_EOF 3
1053 static inline unsigned int
1059 for (i = 0; i < 4; i++)
1069 /* Try to either setup on-demand paging (using FP as backing
1070 file), or in case that doesn't work (FP not seekable) slurps in
1071 all pages and deactivates paging. */
1074 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1076 FILE *fp = data->fp;
1077 unsigned int npages;
1079 unsigned int can_seek;
1081 unsigned char buf[BLOB_PAGESIZE];
1082 if (pagesz != BLOB_PAGESIZE)
1084 /* We could handle this by slurping in everything. */
1085 fprintf (stderr, "non matching page size\n");
1089 if ((cur_file_ofs = ftell(fp)) < 0)
1093 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1095 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1097 data->num_pages = npages;
1098 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1100 /* If we can't seek on our input we have to slurp in everything. */
1102 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1103 for (i = 0; i < npages; i++)
1105 unsigned int in_len = read_u32(fp);
1106 unsigned int compressed = in_len & 1;
1107 Attrblobpage *p = data->pages + i;
1110 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1111 i, in_len, compressed ? "" : "not ");
1117 p->file_offset = cur_file_ofs;
1118 p->file_size = in_len * 2 + compressed;
1119 if (fseek(fp, in_len, SEEK_CUR) < 0)
1122 fprintf (stderr, "can't seek after we thought we can\n");
1123 /* We can't fall back to non-seeking behaviour as we already
1124 read over some data pages without storing them away. */
1127 cur_file_ofs += in_len;
1131 unsigned int out_len;
1132 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1133 p->mapped_at = i * BLOB_PAGESIZE;
1136 /* We can't seek, so suck everything in. */
1137 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1144 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1145 if (out_len != BLOB_PAGESIZE
1148 fprintf (stderr, "can't decompress\n");
1157 /* If we are here we were able to seek to all page
1158 positions, so activate paging by copying FP into our structure.
1159 We dup() the file, so that our callers can fclose() it and we
1160 still have it open. But this means that we share file positions
1161 with the input filedesc. So in case our caller reads it after us,
1162 and calls back into us we might change the file position unexpectedly
1164 int fd = dup (fileno (fp));
1167 /* Jeez! What a bloody system, we can't dup() anymore. */
1171 /* XXX we don't close this yet anywhere. */
1172 data->fp = fdopen (fd, "r");
1175 /* My God! What happened now? */