Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "razor-internal.h"
24 #define UPSTREAM_SOURCE 0x80
27 struct razor_set *set;
28 uint32_t *property_map;
33 struct razor_set *set;
34 struct hashtable table;
35 struct hashtable file_table;
36 struct source source1;
37 struct source source2;
41 razor_merger_create(struct razor_set *set1, struct razor_set *set2)
43 struct razor_merger *merger;
47 merger = zalloc(sizeof *merger);
48 merger->set = razor_set_create();
49 hashtable_init(&merger->table, &merger->set->string_pool);
50 hashtable_init(&merger->file_table, &merger->set->file_string_pool);
52 merger->source1.set = set1;
53 count = set1->properties.size / sizeof (struct razor_property);
54 size = count * sizeof merger->source1.property_map[0];
55 merger->source1.property_map = zalloc(size);
56 count = set1->files.size / sizeof (struct razor_entry);
57 size = count * sizeof merger->source1.file_map[0];
58 merger->source1.file_map = zalloc(size);
60 merger->source2.set = set2;
61 count = set2->properties.size / sizeof (struct razor_property);
62 size = count * sizeof merger->source2.property_map[0];
63 merger->source2.property_map = zalloc(size);
64 count = set2->files.size / sizeof (struct razor_entry);
65 size = count * sizeof merger->source2.file_map[0];
66 merger->source2.file_map = zalloc(size);
72 razor_merger_add_package(struct razor_merger *merger,
73 struct razor_package *package)
77 struct razor_package *p;
78 struct razor_set *set1;
79 struct source *source;
82 set1 = merger->source1.set;
83 if (set1->packages.data <= (void *) package &&
84 (void *) package < set1->packages.data + set1->packages.size) {
85 source = &merger->source1;
88 source = &merger->source2;
89 flags = UPSTREAM_SOURCE;
92 pool = source->set->string_pool.data;
93 p = array_add(&merger->set->packages, sizeof *p);
94 p->name = hashtable_tokenize(&merger->table, &pool[package->name]);
96 p->version = hashtable_tokenize(&merger->table,
97 &pool[package->version]);
98 p->arch = hashtable_tokenize(&merger->table,
99 &pool[package->arch]);
101 p->properties = package->properties;
102 r = list_first(&package->properties, &source->set->property_pool);
104 source->property_map[r->data] = 1;
108 p->files = package->files;
109 r = list_first(&package->files, &source->set->file_pool);
111 source->file_map[r->data] = 1;
117 add_property(struct razor_merger *merger,
118 const char *name, uint32_t flags, const char *version)
120 struct razor_property *p;
122 p = array_add(&merger->set->properties, sizeof *p);
123 p->name = hashtable_tokenize(&merger->table, name);
125 p->version = hashtable_tokenize(&merger->table, version);
127 return p - (struct razor_property *) merger->set->properties.data;
131 merge_properties(struct razor_merger *merger)
133 struct razor_property *p1, *p2;
134 struct razor_set *set1, *set2;
135 uint32_t *map1, *map2;
136 int i, j, cmp, count1, count2;
139 set1 = merger->source1.set;
140 set2 = merger->source2.set;
141 map1 = merger->source1.property_map;
142 map2 = merger->source2.property_map;
146 pool1 = set1->string_pool.data;
147 pool2 = set2->string_pool.data;
149 count1 = set1->properties.size / sizeof *p1;
150 count2 = set2->properties.size / sizeof *p2;
151 while (i < count1 || j < count2) {
152 if (i < count1 && map1[i] == 0) {
156 if (j < count2 && map2[j] == 0) {
160 p1 = (struct razor_property *) set1->properties.data + i;
161 p2 = (struct razor_property *) set2->properties.data + j;
162 if (i < count1 && j < count2)
163 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
169 cmp = p1->flags - p2->flags;
171 cmp = razor_versioncmp(&pool1[p1->version],
172 &pool2[p2->version]);
174 map1[i++] = add_property(merger,
177 &pool1[p1->version]);
178 } else if (cmp > 0) {
179 map2[j++] = add_property(merger,
182 &pool2[p2->version]);
184 map1[i++] = map2[j++] =
188 &pool1[p1->version]);
194 emit_properties(struct list_head *properties, struct array *source_pool,
195 uint32_t *map, struct array *pool)
200 r = pool->size / sizeof *q;
201 p = list_first(properties, source_pool);
203 q = array_add(pool, sizeof *q);
204 q->data = map[p->data];
209 list_set_ptr(properties, r);
213 add_file(struct razor_merger *merger, const char *name)
215 struct razor_entry *e;
217 e = array_add(&merger->set->files, sizeof *e);
218 e->name = hashtable_tokenize(&merger->file_table, name);
222 return e - (struct razor_entry *)merger->set->files.data;
227 fix_file_map(uint32_t *map,
228 struct razor_entry *files,
229 struct razor_entry *top)
236 if (files[e].start &&
237 fix_file_map(map, files, &files[files[e].start]))
241 } while (!(files[e++].flags & RAZOR_ENTRY_LAST));
246 struct merge_directory {
247 uint32_t merged, dir1, dir2;
251 merge_one_directory(struct razor_merger *merger, struct merge_directory *md)
253 struct razor_entry *root1, *root2, *mroot, *e1, *e2;
254 struct razor_set *set1, *set2;
255 struct array merge_stack;
256 struct merge_directory *child_md, *end_md;
257 uint32_t *map1, *map2, start, last;
261 set1 = merger->source1.set;
262 set2 = merger->source2.set;
263 map1 = merger->source1.file_map;
264 map2 = merger->source2.file_map;
265 pool1 = set1->file_string_pool.data;
266 pool2 = set2->file_string_pool.data;
267 root1 = (struct razor_entry *) set1->files.data;
268 root2 = (struct razor_entry *) set2->files.data;
270 array_init(&merge_stack);
272 start = merger->set->files.size / sizeof (struct razor_entry);
274 e1 = md->dir1 != 0xFFFFFFFF ? root1 + md->dir1 : NULL;
275 e2 = md->dir2 != 0xFFFFFFFF ? root2 + md->dir2 : NULL;
277 if (!e2 && !map1[e1 - root1]) {
278 if ((e1++)->flags & RAZOR_ENTRY_LAST)
282 if (!e1 && !map2[e2 - root2]) {
283 if ((e2++)->flags & RAZOR_ENTRY_LAST)
287 if (e1 && !map1[e1 - root1] &&
288 e2 && !map2[e2 - root2]) {
289 if ((e1++)->flags & RAZOR_ENTRY_LAST)
291 if ((e2++)->flags & RAZOR_ENTRY_LAST)
301 cmp = strcmp (&pool1[e1->name],
306 if (map1[e1 - root1]) {
307 map1[e1 - root1] = last =
308 add_file(merger, &pool1[e1->name]);
310 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
311 child_md->merged = last;
312 child_md->dir1 = e1->start;
313 child_md->dir2 = 0xFFFFFFFF;
316 if ((e1++)->flags & RAZOR_ENTRY_LAST)
318 } else if (cmp > 0) {
319 if (map2[e2 - root2]) {
320 map2[e2 - root2] = last =
321 add_file(merger, &pool2[e2->name]);
323 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
324 child_md->merged = last;
325 child_md->dir1 = 0xFFFFFFFF;
326 child_md->dir2 = e2->start;
329 if ((e2++)->flags & RAZOR_ENTRY_LAST)
332 map1[e1 - root1] = map2[e2- root2] = last =
333 add_file(merger, &pool1[e1->name]);
334 if (e1->start || e2->start) {
335 child_md = array_add(&merge_stack, sizeof (struct merge_directory));
336 child_md->merged = last;
337 child_md->dir1 = e1->start ? e1->start : 0xFFFFFFFF;
338 child_md->dir2 = e2->start ? e2->start : 0xFFFFFFFF;
340 if ((e1++)->flags & RAZOR_ENTRY_LAST)
342 if ((e2++)->flags & RAZOR_ENTRY_LAST)
347 mroot = (struct razor_entry *)merger->set->files.data;
348 if (last != 0xFFFFFFFF) {
349 mroot[last].flags = RAZOR_ENTRY_LAST;
350 mroot[md->merged].start = start;
353 end_md = merge_stack.data + merge_stack.size;
354 for (child_md = merge_stack.data; child_md < end_md; child_md++)
355 merge_one_directory(merger, child_md);
356 array_release(&merge_stack);
360 merge_files(struct razor_merger *merger)
362 struct razor_entry *root;
363 struct merge_directory md;
364 uint32_t *map1, *map2;
366 map1 = merger->source1.file_map;
367 map2 = merger->source2.file_map;
371 if (merger->source1.set->files.size) {
372 root = (struct razor_entry *) merger->source1.set->files.data;
374 fix_file_map(map1, root, root);
377 md.dir1 = 0xFFFFFFFF;
380 if (merger->source2.set->files.size) {
381 root = (struct razor_entry *) merger->source2.set->files.data;
383 fix_file_map(map2, root, root);
386 md.dir2 = 0xFFFFFFFF;
389 /* Remove the unnamed root which razor_set_create() added */
390 array_release(&merger->set->files);
391 array_init(&merger->set->files);
393 merge_one_directory(merger, &md);
397 emit_files(struct list_head *files, struct array *source_pool,
398 uint32_t *map, struct array *pool)
403 r = pool->size / sizeof *q;
404 p = list_first(files, source_pool);
406 q = array_add(pool, sizeof *q);
407 q->data = map[p->data];
412 list_set_ptr(files, r);
415 /* Rebuild property->packages maps. We can't just remap these, as a
416 * property may have lost or gained a number of packages. Allocate an
417 * array per property and loop through the packages and add them to
418 * the arrays for their properties. */
420 rebuild_property_package_lists(struct razor_set *set)
422 struct array *pkgs, *a;
423 struct razor_package *pkg, *pkg_end;
424 struct razor_property *prop, *prop_end;
429 count = set->properties.size / sizeof (struct razor_property);
430 pkgs = zalloc(count * sizeof *pkgs);
431 pkg_end = set->packages.data + set->packages.size;
433 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
434 r = list_first(&pkg->properties, &set->property_pool);
436 q = array_add(&pkgs[r->data], sizeof *q);
437 *q = pkg - (struct razor_package *) set->packages.data;
442 prop_end = set->properties.data + set->properties.size;
444 for (prop = set->properties.data; prop < prop_end; prop++, a++) {
445 list_set_array(&prop->packages, &set->package_pool, a, 0);
452 rebuild_file_package_lists(struct razor_set *set)
454 struct array *pkgs, *a;
455 struct razor_package *pkg, *pkg_end;
456 struct razor_entry *entry, *entry_end;
461 count = set->files.size / sizeof (struct razor_entry);
462 pkgs = zalloc(count * sizeof *pkgs);
463 pkg_end = set->packages.data + set->packages.size;
465 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
466 r = list_first(&pkg->files, &set->file_pool);
468 q = array_add(&pkgs[r->data], sizeof *q);
469 *q = pkg - (struct razor_package *) set->packages.data;
474 entry_end = set->files.data + set->files.size;
476 for (entry = set->files.data; entry < entry_end; entry++, a++) {
477 list_set_array(&entry->packages, &set->package_pool, a, 0);
484 razor_merger_finish(struct razor_merger *merger)
486 struct razor_set *result;
487 struct razor_package *p, *pend;
489 /* As we built the package list, we filled out a bitvector of
490 * the properties that are referenced by the packages in the
491 * new set. Now we do a parallel loop through the properties
492 * and emit those marked in the bit vector to the new set. In
493 * the process, we update the bit vector to actually map from
494 * indices in the old property list to indices in the new
495 * property list for both sets. */
497 merge_properties(merger);
500 /* Now we loop through the packages again and emit the
501 * property lists, remapped to point to the new properties. */
503 pend = merger->set->packages.data + merger->set->packages.size;
504 for (p = merger->set->packages.data; p < pend; p++) {
507 if (p->flags & UPSTREAM_SOURCE)
508 src = &merger->source2;
510 src = &merger->source1;
512 emit_properties(&p->properties,
513 &src->set->property_pool,
515 &merger->set->property_pool);
516 emit_files(&p->files,
517 &src->set->file_pool,
519 &merger->set->file_pool);
520 p->flags &= ~UPSTREAM_SOURCE;
523 rebuild_property_package_lists(merger->set);
524 rebuild_file_package_lists(merger->set);
526 result = merger->set;
527 hashtable_release(&merger->table);
528 hashtable_release(&merger->file_table);