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);
403 maybe_load_repodata(Repodata *data)
405 if (data->state == REPODATA_STUB)
407 if (data->loadcallback)
408 data->loadcallback(data);
410 data->state = REPODATA_ERROR;
412 if (data->state == REPODATA_AVAILABLE)
414 data->state = REPODATA_ERROR;
419 repodata_lookup_str(Repodata *data, Id entry, Id keyid)
426 if (!maybe_load_repodata (data))
429 dp = data->incoredata + data->incoreoffset[entry];
430 dp = data_read_id(dp, &schema);
431 /* make sure the schema of this solvable contains the key */
432 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
435 dp = forward_to_key(data, keyid, schema, dp);
436 key = data->keys + keyid;
437 dp = get_data(data, key, &dp);
440 if (key->type == TYPE_STR)
441 return (const char *)dp;
442 if (key->type != TYPE_ID)
444 /* id type, must either use global or local string store*/
445 dp = data_read_id(dp, &id);
447 return data->spool.stringspace + data->spool.strings[id];
448 return id2str(data->repo->pool, id);
452 repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned *value)
462 if (!maybe_load_repodata (data))
465 dp = data->incoredata + data->incoreoffset[entry];
466 dp = data_read_id(dp, &schema);
467 /* make sure the schema of this solvable contains the key */
468 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
471 dp = forward_to_key(data, keyid, schema, dp);
472 key = data->keys + keyid;
473 dp = get_data(data, key, &dp);
476 if (key->type == TYPE_NUM
477 || key->type == TYPE_U32
478 || key->type == TYPE_CONSTANT)
480 dp = data_fetch(dp, &kv, key);
488 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
492 Id k, keyid, *kp, *keyp;
493 unsigned char *dp, *ddp;
498 if (!maybe_load_repodata (data))
501 dp = data->incoredata + data->incoreoffset[entry];
502 dp = data_read_id(dp, &schema);
503 keyp = data->schemadata + data->schemata[schema];
506 /* search in a specific key */
507 for (kp = keyp; (k = *kp++) != 0; )
508 if (data->keys[k].name == keyname)
512 dp = forward_to_key(data, k, schema, dp);
518 while ((keyid = *keyp++) != 0)
521 key = data->keys + keyid;
522 ddp = get_data(data, key, &dp);
525 ddp = data_fetch(ddp, &kv, key);
528 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
530 while (!kv.eof && !stop);
531 if (onekey || stop > SEARCH_NEXT_KEY)
537 /* extend repodata so that it includes solvables p */
539 repodata_extend(Repodata *data, Id p)
541 if (data->start == data->end)
542 data->start = data->end = p;
545 int old = data->end - data->start;
546 int new = p - data->end + 1;
549 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
550 memset(data->attrs + old, 0, new * sizeof(Id *));
552 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
553 memset(data->incoreoffset + old, 0, new * sizeof(Id));
558 int old = data->end - data->start;
559 int new = data->start - p;
562 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
563 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
564 memset(data->attrs, 0, new * sizeof(Id *));
566 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
567 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
568 memset(data->incoreoffset, 0, new * sizeof(Id));
574 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
579 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
581 if (data->attrs[entry])
583 for (pp = data->attrs[entry]; *pp; pp += 2)
584 /* Determine equality based on the name only, allows us to change
585 type (when overwrite is set), and makes TYPE_CONSTANT work. */
586 if (data->keys[*pp].name == data->keys[keyid].name)
597 i = pp - data->attrs[entry];
599 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
600 pp = data->attrs[entry] + i;
607 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
611 /* find key in keys */
612 for (keyid = 1; keyid < data->nkeys; keyid++)
613 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
615 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
619 if (keyid == data->nkeys)
621 /* allocate new key */
622 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
623 data->keys[data->nkeys++] = *key;
624 if (data->verticaloffset)
626 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
627 data->verticaloffset[data->nkeys - 1] = 0;
630 repodata_insert_keyid(data, entry, keyid, val, 1);
634 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
640 key.storage = KEY_STORAGE_INCORE;
641 repodata_set(data, entry, &key, id);
645 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
651 key.storage = KEY_STORAGE_INCORE;
652 repodata_set(data, entry, &key, num);
656 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
661 id = stringpool_str2id(&data->spool, str, 1);
663 id = str2id(data->repo->pool, str, 1);
667 key.storage = KEY_STORAGE_INCORE;
668 repodata_set(data, entry, &key, id);
672 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
676 key.type = TYPE_CONSTANT;
678 key.storage = KEY_STORAGE_INCORE;
679 repodata_set(data, entry, &key, 0);
683 repodata_set_void(Repodata *data, Id entry, Id keyname)
687 key.type = TYPE_VOID;
689 key.storage = KEY_STORAGE_INCORE;
690 repodata_set(data, entry, &key, 0);
694 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
703 key.storage = KEY_STORAGE_INCORE;
704 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
705 memcpy(data->attrdata + data->attrdatalen, str, l);
706 repodata_set(data, entry, &key, data->attrdatalen);
707 data->attrdatalen += l;
711 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
717 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
719 if (data->attrs && data->attrs[entry])
721 for (pp = data->attrs[entry]; *pp; pp += 2)
722 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
727 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
729 if (ida + 1 == data->attriddata + data->attriddatalen)
731 /* this was the last entry, just append it */
732 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
733 data->attriddatalen--; /* overwrite terminating 0 */
737 /* too bad. move to back. */
738 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
739 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
740 pp[1] = data->attriddatalen;
741 data->attriddatalen += oldsize;
743 data->attriddata[data->attriddatalen++] = dir;
744 data->attriddata[data->attriddatalen++] = num;
745 data->attriddata[data->attriddatalen++] = num2;
746 data->attriddata[data->attriddatalen++] = 0;
751 key.type = TYPE_DIRNUMNUMARRAY;
753 key.storage = KEY_STORAGE_INCORE;
754 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
755 repodata_set(data, entry, &key, data->attriddatalen);
756 data->attriddata[data->attriddatalen++] = dir;
757 data->attriddata[data->attriddatalen++] = num;
758 data->attriddata[data->attriddatalen++] = num2;
759 data->attriddata[data->attriddatalen++] = 0;
763 repodata_merge_attrs (Repodata *data, Id dest, Id src)
766 for (keyp = data->attrs[src]; *keyp; keyp += 2)
767 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
770 /*********************************/
772 /* unify with repo_write! */
774 #define EXTDATA_BLOCK 1023
775 #define SCHEMATA_BLOCK 31
776 #define SCHEMATADATA_BLOCK 255
784 data_addid(struct extdata *xd, Id x)
787 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
788 dp = xd->buf + xd->len;
793 *dp++ = (x >> 28) | 128;
795 *dp++ = (x >> 21) | 128;
796 *dp++ = (x >> 14) | 128;
799 *dp++ = (x >> 7) | 128;
801 xd->len = dp - xd->buf;
805 data_addideof(struct extdata *xd, Id x, int eof)
808 x = (x & 63) | ((x & ~63) << 1);
809 data_addid(xd, (eof ? x: x | 64));
813 data_addblob(struct extdata *xd, unsigned char *blob, int len)
815 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
816 memcpy(xd->buf + xd->len, blob, len);
820 /*********************************/
823 addschema_prepare(Repodata *data, Id *schematacache)
828 memset(schematacache, 0, 256 * sizeof(Id));
829 for (i = 0; i < data->nschemata; i++)
831 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
834 schematacache[h] = i + 1;
836 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
837 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
841 addschema(Repodata *data, Id *schema, Id *schematacache)
846 for (sp = schema, len = 0, h = 0; *sp; len++)
851 cid = schematacache[h];
855 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
858 for (cid = 0; cid < data->nschemata; cid++)
859 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
862 /* a new one. make room. */
863 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
864 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
866 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
867 data->schemata[data->nschemata] = data->schemadatalen;
868 data->schemadatalen += len;
869 schematacache[h] = data->nschemata + 1;
871 fprintf(stderr, "addschema: new schema\n");
873 return data->nschemata++;
878 repodata_internalize(Repodata *data)
881 Id id, entry, nentry, *ida;
882 Id schematacache[256];
883 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
884 unsigned char *dp, *ndp;
885 int newschema, oldcount;
886 struct extdata newincore;
887 struct extdata newvincore;
892 newvincore.buf = data->vincore;
893 newvincore.len = data->vincorelen;
895 schema = sat_malloc2(data->nkeys, sizeof(Id));
896 seen = sat_malloc2(data->nkeys, sizeof(Id));
898 /* Merge the data already existing (in data->schemata, ->incoredata and
899 friends) with the new attributes in data->attrs[]. */
900 nentry = data->end - data->start;
901 addschema_prepare(data, schematacache);
902 memset(&newincore, 0, sizeof(newincore));
903 for (entry = 0; entry < nentry; entry++)
905 memset(seen, 0, data->nkeys * sizeof(Id));
907 dp = data->incoredata + data->incoreoffset[entry];
908 if (data->incoredata)
909 dp = data_read_id(dp, &oldschema);
913 fprintf(stderr, "oldschema %d\n", oldschema);
914 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
915 fprintf(stderr, "schemadata %p\n", data->schemadata);
917 /* seen: -1: old data 0: skipped >0: id + 1 */
920 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
924 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
931 if (data->attrs[entry])
932 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
939 seen[*keyp] = keyp[1] + 1;
943 /* Ideally we'd like to sort the new schema here, to ensure
944 schema equality independend of the ordering. We can't do that
945 yet. For once see below (old ids need to come before new ids).
946 An additional difficulty is that we also need to move
947 the values with the keys. */
948 schemaid = addschema(data, schema, schematacache);
950 schemaid = oldschema;
953 /* Now create data blob. We walk through the (possibly new) schema
954 and either copy over old data, or insert the new. */
955 /* XXX Here we rely on the fact that the (new) schema has the form
956 o1 o2 o3 o4 ... | n1 n2 n3 ...
957 (oX being the old keyids (possibly overwritten), and nX being
958 the new keyids). This rules out sorting the keyids in order
959 to ensure a small schema count. */
960 data->incoreoffset[entry] = newincore.len;
961 data_addid(&newincore, schemaid);
962 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
964 key = data->keys + *keyp;
968 /* Skip the data associated with this old key. */
969 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
971 ndp = data_skip(dp, TYPE_ID);
972 ndp = data_skip(ndp, TYPE_ID);
974 else if (key->storage == KEY_STORAGE_INCORE)
975 ndp = data_skip(dp, key->type);
978 if (seen[*keyp] == -1)
980 /* If this key was an old one _and_ was not overwritten with
981 a different value copy over the old value (we skipped it
984 data_addblob(&newincore, dp, ndp - dp);
987 else if (seen[*keyp])
989 /* Otherwise we have a new value. Parse it into the internal
992 unsigned int oldvincorelen = 0;
995 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
998 oldvincorelen = xd->len;
1000 id = seen[*keyp] - 1;
1007 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1014 case TYPE_DIRNUMNUMARRAY:
1015 for (ida = data->attriddata + id; *ida; ida += 3)
1017 data_addid(xd, ida[0]);
1018 data_addid(xd, ida[1]);
1019 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1023 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1026 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1028 /* put offset/len in incore */
1029 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1030 oldvincorelen = xd->len - oldvincorelen;
1031 data_addid(&newincore, oldvincorelen);
1037 data->incoredata = newincore.buf;
1038 data->incoredatalen = newincore.len;
1039 data->incoredatafree = 0;
1041 data->vincore = newvincore.buf;
1042 data->vincorelen = newvincore.len;
1044 data->attrs = sat_free(data->attrs);
1045 data->attrdata = sat_free(data->attrdata);
1046 data->attrdatalen = 0;
1050 repodata_str2dir(Repodata *data, const char *dir, int create)
1056 while (*dir == '/' && dir[1] == '/')
1060 dire = strchrnul(dir, '/');
1061 if (data->localpool)
1062 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1064 id = strn2id(data->repo->pool, dir, dire - dir, create);
1067 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1080 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1082 return compress_buf(page, len, cpage, max);
1085 #define SOLV_ERROR_EOF 3
1087 static inline unsigned int
1093 for (i = 0; i < 4; i++)
1103 /* Try to either setup on-demand paging (using FP as backing
1104 file), or in case that doesn't work (FP not seekable) slurps in
1105 all pages and deactivates paging. */
1108 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1110 FILE *fp = data->fp;
1111 unsigned int npages;
1113 unsigned int can_seek;
1115 unsigned char buf[BLOB_PAGESIZE];
1116 if (pagesz != BLOB_PAGESIZE)
1118 /* We could handle this by slurping in everything. */
1119 fprintf (stderr, "non matching page size\n");
1123 if ((cur_file_ofs = ftell(fp)) < 0)
1127 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1129 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1131 data->num_pages = npages;
1132 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1134 /* If we can't seek on our input we have to slurp in everything. */
1136 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1137 for (i = 0; i < npages; i++)
1139 unsigned int in_len = read_u32(fp);
1140 unsigned int compressed = in_len & 1;
1141 Attrblobpage *p = data->pages + i;
1144 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1145 i, in_len, compressed ? "" : "not ");
1151 p->file_offset = cur_file_ofs;
1152 p->file_size = in_len * 2 + compressed;
1153 if (fseek(fp, in_len, SEEK_CUR) < 0)
1156 fprintf (stderr, "can't seek after we thought we can\n");
1157 /* We can't fall back to non-seeking behaviour as we already
1158 read over some data pages without storing them away. */
1161 cur_file_ofs += in_len;
1165 unsigned int out_len;
1166 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1167 p->mapped_at = i * BLOB_PAGESIZE;
1170 /* We can't seek, so suck everything in. */
1171 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1178 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1179 if (out_len != BLOB_PAGESIZE
1182 fprintf (stderr, "can't decompress\n");
1191 /* If we are here we were able to seek to all page
1192 positions, so activate paging by copying FP into our structure.
1193 We dup() the file, so that our callers can fclose() it and we
1194 still have it open. But this means that we share file positions
1195 with the input filedesc. So in case our caller reads it after us,
1196 and calls back into us we might change the file position unexpectedly
1198 int fd = dup (fileno (fp));
1201 /* Jeez! What a bloody system, we can't dup() anymore. */
1205 /* XXX we don't close this yet anywhere. */
1206 data->fp = fdopen (fd, "r");
1209 /* My God! What happened now? */