librazor/importer.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Jul 08 15:54:49 2016 +0100 (2016-07-08)
changeset 482 6a8a57779674
parent 458 3f841a46eab5
permissions -rw-r--r--
Release 0.6.3.101
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #define _GNU_SOURCE
    22 
    23 #include "config.h"
    24 #include <string.h>
    25 #include "razor-internal.h"
    26 #include "razor.h"
    27 
    28 /**
    29  * razor_importer_create:
    30  *
    31  * Create a new %razor_importer.
    32  *
    33  * Returns: the new %razor_importer.
    34  **/
    35 RAZOR_EXPORT struct razor_importer *
    36 razor_importer_create(void)
    37 {
    38 	struct razor_importer *importer;
    39 
    40 	importer = zalloc(sizeof *importer);
    41 	importer->set = razor_set_create();
    42 	hashtable_init(&importer->table, &importer->set->string_pool);
    43 	hashtable_init(&importer->details_table,
    44 		       &importer->set->details_string_pool);
    45 	hashtable_init(&importer->file_table,
    46 		       &importer->set->file_string_pool);
    47 
    48 	return importer;
    49 }
    50 
    51 /**
    52  * razor_importer_destroy:
    53  * @importer: the %razor_importer
    54  *
    55  * Destroy an importer without creating a %razor_set.  Normally,
    56  * %razor_importer_finish will create a new %razor_set and destroy the
    57  * importer.  If the import must be aborted without creating the set,
    58  * just destroy the import using this function.
    59  **/
    60 RAZOR_EXPORT void
    61 razor_importer_destroy(struct razor_importer *importer)
    62 {
    63 	struct import_entry *e, *end;
    64 
    65 	razor_set_unref(importer->set);
    66 	hashtable_release(&importer->table);
    67 	hashtable_release(&importer->details_table);
    68 	hashtable_release(&importer->file_table);
    69 
    70 	e = importer->files.data;
    71 	end = importer->files.data + importer->files.size;
    72 	while (e < end) {
    73 		free(e->name);
    74 		e++;
    75 	}
    76 	array_release(&importer->files);
    77 	array_release(&importer->file_requires);
    78 
    79 	if (importer->package) {
    80 		array_release(&importer->properties);
    81 		array_release(&importer->install_prefixes);
    82 	}
    83 
    84 	free(importer);
    85 }
    86 
    87 
    88 /**
    89  * razor_importer_begin_package:
    90  * @importer: the %razor_importer
    91  * @name: the name of the new package
    92  * @version: the version of the new package
    93  * @arch: the architechture of the new package.
    94  *
    95  * Begin describing a new package to the importer.  This creates a new
    96  * package and sets the %name, %version and %arch.  Subsequent calls
    97  * to %razor_importer_add_details, %razor_importer_add_property and
    98  * %razor_importer_add_file further describe this package and
    99  * %razor_importer_finish_package marks the end of meta data for this
   100  * package.
   101  **/
   102 RAZOR_EXPORT void
   103 razor_importer_begin_package(struct razor_importer *importer,
   104 			     const char *name,
   105 			     const char *version,
   106 			     const char *arch)
   107 {
   108 	uint32_t empty;
   109 	struct razor_package *p;
   110 
   111 	p = array_add(&importer->set->packages, sizeof *p);
   112 	p->name = hashtable_tokenize(&importer->table, name);
   113 	p->flags = 0;
   114 	p->version = hashtable_tokenize(&importer->table, version);
   115 	p->arch = hashtable_tokenize(&importer->table, arch);
   116 
   117 	importer->package = p;
   118 	array_init(&importer->properties);
   119 	array_init(&importer->install_prefixes);
   120 
   121 	empty = hashtable_tokenize(&importer->details_table, "");
   122 	importer->package->preun.program = empty;
   123 	importer->package->preun.body = empty;
   124 	importer->package->postun.program = empty;
   125 	importer->package->postun.body = empty;
   126 }
   127 
   128 /**
   129  * razor_importer_finish_package:
   130  * @importer: the %razor_importer
   131  *
   132  * Tells the importer that the current package is complete.
   133  **/
   134 RAZOR_EXPORT void
   135 razor_importer_finish_package(struct razor_importer *importer)
   136 {
   137 	list_set_array(&importer->package->properties,
   138 		       &importer->set->property_pool,
   139 		       &importer->properties,
   140 		       1);
   141 
   142 	list_set_array(&importer->package->install_prefixes,
   143 		       &importer->set->prefix_pool,
   144 		       &importer->install_prefixes,
   145 		       0);
   146 
   147 	array_release(&importer->properties);
   148 	array_release(&importer->install_prefixes);
   149 
   150 	importer->package = NULL;
   151 }
   152 
   153 /**
   154  * razor_importer_add_details:
   155  * @importer: the %razor_importer
   156  * @summary: the package summary
   157  * @description: the package description
   158  * @url: the package url
   159  * @license: the package license
   160  *
   161  * Provide additional information for the current package.
   162  **/
   163 RAZOR_EXPORT void
   164 razor_importer_add_details(struct razor_importer *importer,
   165 			   const char *summary,
   166 			   const char *description,
   167 			   const char *url,
   168 			   const char *license)
   169 {
   170 	importer->package->summary = hashtable_tokenize(&importer->details_table, summary);
   171 	importer->package->description = hashtable_tokenize(&importer->details_table, description);
   172 	importer->package->url = hashtable_tokenize(&importer->details_table, url);
   173 	importer->package->license = hashtable_tokenize(&importer->details_table, license);
   174 }
   175 
   176 /**
   177  * razor_importer_add_script:
   178  * @importer: the %razor_importer
   179  * @script: either %RAZOR_PROPERTY_PREUN or %RAZOR_PROPERTY_POSTUN
   180  * @program: the program to run the script
   181  * @body: the body of the script
   182  *
   183  * Provide a script to use when uninstalling the current package.
   184  **/
   185 RAZOR_EXPORT void
   186 razor_importer_add_script(struct razor_importer *importer,
   187 			  enum razor_property_flags script,
   188 			  const char *program,
   189 			  const char *body)
   190 {
   191 	switch (script) {
   192 	case RAZOR_PROPERTY_PREUN:
   193 		importer->package->preun.program =
   194 			hashtable_tokenize(&importer->table, program);
   195 		importer->package->preun.body =
   196 			hashtable_tokenize(&importer->table, body);
   197 		break;
   198 	case RAZOR_PROPERTY_POSTUN:
   199 		importer->package->postun.program =
   200 			hashtable_tokenize(&importer->table, program);
   201 		importer->package->postun.body =
   202 			hashtable_tokenize(&importer->table, body);
   203 		break;
   204 	default:
   205 		break;
   206 	}
   207 }
   208 
   209 /**
   210  * razor_importer_add_install_prefixes:
   211  * @importer: the %razor_importer
   212  * @install_prefix: the relocated prefix
   213  *
   214  * Adds a relocated prefix for the current package.
   215  **/
   216 RAZOR_EXPORT void
   217 razor_importer_add_install_prefix(struct razor_importer *importer,
   218 				  const char *install_prefix)
   219 {
   220 	uint32_t *r;
   221 
   222 	r = array_add(&importer->install_prefixes, sizeof *r);
   223 	*r = hashtable_tokenize(&importer->table, install_prefix);
   224 }
   225 
   226 /**
   227  * razor_importer_add_property:
   228  * @importer: the %razor_importer
   229  * @name: name of the property
   230  * @flags: property flags
   231  * @version: version of the property or %NULL
   232  *
   233  * Add a property for the current package.  The %flags parameter
   234  * determines the type of the property and optionally the relation to
   235  * the specified version and the availability constraint.  See
   236  * %razor_property_flags for further information about the flag
   237  * parameter.
   238  **/
   239 RAZOR_EXPORT void
   240 razor_importer_add_property(struct razor_importer *importer,
   241 			    const char *name,
   242 			    uint32_t flags,
   243 			    const char *version)
   244 {
   245 	struct razor_property *p;
   246 	uint32_t *r;
   247 
   248 	p = array_add(&importer->set->properties, sizeof *p);
   249 	p->name = hashtable_tokenize(&importer->table, name);
   250 	p->flags = flags;
   251 	p->version = hashtable_tokenize(&importer->table, version);
   252 	list_set_ptr(&p->packages, importer->package -
   253 		     (struct razor_package *) importer->set->packages.data);
   254 
   255 	r = array_add(&importer->properties, sizeof *r);
   256 	*r = p - (struct razor_property *) importer->set->properties.data;
   257 
   258 	if (((flags & RAZOR_PROPERTY_TYPE_MASK) == RAZOR_PROPERTY_REQUIRES) &&
   259 	    *name == '/') {
   260 		r = array_add(&importer->file_requires, sizeof *r);
   261 		*r = p->name;
   262 	}
   263 }
   264 
   265 /**
   266  * razor_importer_add_file:
   267  * @importer: the %razor_importer
   268  * @name: name of the file
   269  *
   270  * Add a file to the current package.
   271  **/
   272 RAZOR_EXPORT void
   273 razor_importer_add_file(struct razor_importer *importer, const char *name)
   274 {
   275 	struct import_entry *e;
   276 
   277 	e = array_add(&importer->files, sizeof *e);
   278 
   279 	e->package = importer->package -
   280 		(struct razor_package *) importer->set->packages.data;
   281 	e->name = strdup(name);
   282 }
   283 
   284 static int
   285 compare_packages(const void *p1, const void *p2, void *data)
   286 {
   287 	const struct razor_package *pkg1 = p1, *pkg2 = p2;
   288 	struct razor_set *set = data;
   289 	char *pool = set->string_pool.data;
   290 
   291 	/* FIXME: what if the flags are different? */
   292 	if (pkg1->name == pkg2->name)
   293 		return razor_versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
   294 	else
   295 		return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
   296 }
   297 
   298 static int
   299 compare_properties(const void *p1, const void *p2, void *data)
   300 {
   301 	const struct razor_property *prop1 = p1, *prop2 = p2;
   302 	struct razor_set *set = data;
   303 	char *pool = set->string_pool.data;
   304 
   305 	if (prop1->name != prop2->name)
   306 		return strcmp(&pool[prop1->name], &pool[prop2->name]);
   307 	else if (prop1->flags != prop2->flags)
   308 		return prop1->flags - prop2->flags;
   309 	else if (prop1->version != prop2->version)
   310 		return razor_versioncmp(&pool[prop1->version], &pool[prop2->version]);
   311 	else
   312 		return prop1->packages.list_ptr - prop2->packages.list_ptr;
   313 }
   314 
   315 static uint32_t *
   316 uniqueify_properties(struct razor_set *set)
   317 {
   318 	struct razor_property *rp, *up, *rp_end;
   319 	struct array *pkgs, *p;
   320 	struct list_head *r;
   321 	uint32_t *map, *rmap;
   322 	int i, count, unique;
   323 
   324 	count = set->properties.size / sizeof(struct razor_property);
   325 	map = razor_qsort_with_data(set->properties.data,
   326 				    count,
   327 				    sizeof(struct razor_property),
   328 				    compare_properties,
   329 				    set);
   330 
   331 	rp_end = set->properties.data + set->properties.size;
   332 	rmap = malloc(count * sizeof *map);
   333 	pkgs = zalloc(count * sizeof *pkgs);
   334 	for (rp = set->properties.data, up = rp, i = 0; rp < rp_end; rp++, i++) {
   335 		if (rp->name != up->name ||
   336 		    rp->flags != up->flags ||
   337 		    rp->version != up->version) {
   338 			up++;
   339 			up->name = rp->name;
   340 			up->flags = rp->flags;
   341 			up->version = rp->version;
   342 		}
   343 
   344 		unique = up - (struct razor_property *) set->properties.data;
   345 		rmap[map[i]] = unique;
   346 		r = array_add(&pkgs[unique], sizeof *r);
   347 		*r = rp->packages;
   348 	}
   349 	free(map);
   350 
   351 	if (up != rp)
   352 		up++;
   353 	set->properties.size = (void *) up - set->properties.data;
   354 	rp_end = up;
   355 	for (rp = set->properties.data, p = pkgs; rp < rp_end; rp++, p++) {
   356 		list_set_array(&rp->packages, &set->package_pool, p, 0);
   357 		array_release(p);
   358 	}
   359 
   360 	free(pkgs);
   361 
   362 	return rmap;
   363 }
   364 
   365 static int
   366 compare_filenames(const void *p1, const void *p2, void *data)
   367 {
   368 	const struct import_entry *e1 = p1;
   369 	const struct import_entry *e2 = p2;
   370 	const char *n1 = e1->name;
   371 	const char *n2 = e2->name;
   372 
   373 	/* Need to make sure that the contents of a directory
   374 	 * are sorted immediately after it. So "foo/bar" has to
   375 	 * sort before "foo.conf"
   376 	 *
   377 	 * FIXME: this is about 60% slower than strcmp
   378 	 */
   379 	while (*n1 && *n2) {
   380 		if (*n1 < *n2)
   381 			return *n2 == '/' ? 1 : -1;
   382 		else if (*n1 > *n2)
   383 			return *n1 == '/' ? -1 : 1;
   384 		n1++;
   385 		n2++;
   386 	}
   387 	if (*n1)
   388 		return 1;
   389 	else if (*n2)
   390 		return -1;
   391 	else
   392 		return 0;
   393 }
   394 
   395 static void
   396 count_entries(struct import_directory *d)
   397 {
   398 	struct import_directory *p, *end;
   399 
   400 	p = d->files.data;
   401 	end = d->files.data + d->files.size;
   402 	d->count = 0;
   403 	while (p < end) {
   404 		count_entries(p);
   405 		d->count += p->count + 1;
   406 		p++;
   407 	}
   408 }
   409 
   410 static void
   411 serialize_files(struct razor_set *set,
   412 		struct import_directory *d, struct array *array)
   413 {
   414 	struct import_directory *p, *end;
   415 	struct razor_entry *e = NULL;
   416 	uint32_t s;
   417 
   418 	p = d->files.data;
   419 	end = d->files.data + d->files.size;
   420 	s = array->size / sizeof *e + d->files.size / sizeof *p;
   421 	while (p < end) {
   422 		e = array_add(array, sizeof *e);
   423 		e->name = p->name;
   424 		e->flags = 0;
   425 		e->start = p->count > 0 ? s : 0;
   426 		s += p->count;
   427 
   428 		list_set_array(&e->packages, &set->package_pool, &p->packages, 0);
   429 		array_release(&p->packages);
   430 		p++;
   431 	}
   432 	if (e != NULL)
   433 		e->flags |= RAZOR_ENTRY_LAST;
   434 
   435 	p = d->files.data;
   436 	end = d->files.data + d->files.size;
   437 	while (p < end) {
   438 		serialize_files(set, p, array);
   439 		p++;
   440 	}
   441 
   442 	array_release(&d->files);
   443 }
   444 
   445 static void
   446 remap_property_package_links(struct array *properties, uint32_t *rmap)
   447 {
   448 	struct razor_property *p, *end;
   449 
   450 	end = properties->data + properties->size;
   451 	for (p = properties->data; p < end; p++)
   452 		list_remap_head(&p->packages, rmap);
   453 }
   454 
   455 static void
   456 build_file_tree(struct razor_importer *importer)
   457 {
   458 	int count, i, length;
   459 	struct import_entry *filenames;
   460 	char *f, *end;
   461 	uint32_t name, *r, s;
   462 	uint32_t *map;
   463 	char dirname[256];
   464 	struct import_directory *d, *last_root;
   465 	struct array roots;
   466 	struct razor_entry *e;
   467 
   468 	count = importer->files.size / sizeof (struct import_entry);
   469 	filenames = importer->files.data;
   470 	map = razor_qsort_with_data(filenames,
   471 				    count,
   472 				    sizeof (struct import_entry),
   473 				    compare_filenames,
   474 				    NULL);
   475 	free(map);
   476 
   477 	array_init(&roots);
   478 	last_root = NULL;
   479 
   480 	for (i = 0; i < count; i++) {
   481 		f = filenames[i].name;
   482 		d = NULL;
   483 		while (*f) {
   484 			end = strchr(f, '/');
   485 			if (end == NULL)
   486 				end = f + strlen(f);
   487 			length = end - f;
   488 			memcpy(dirname, f, length);
   489 			dirname[length] = '\0';
   490 			name = hashtable_tokenize(&importer->file_table,
   491 						  dirname);
   492 			if (!d) {
   493 				if (!last_root || last_root->name != name) {
   494 					d = array_add(&roots, sizeof *d);
   495 					d->name = name;
   496 					d->last = NULL;
   497 					array_init(&d->files);
   498 					array_init(&d->packages);
   499 					last_root = d;
   500 				}
   501 				d = last_root;
   502 			} else {
   503 				if (!d->last || d->last->name != name) {
   504 					d->last = array_add(&d->files,
   505 							    sizeof *d);
   506 					d->last->name = name;
   507 					d->last->last = NULL;
   508 					array_init(&d->last->files);
   509 					array_init(&d->last->packages);
   510 				}
   511 				d = d->last;
   512 			}
   513 			f = end + 1;
   514 			if (*end == '\0')
   515 				break;
   516 		}
   517 
   518 		r = array_add(&d->packages, sizeof *r);
   519 		*r = filenames[i].package;
   520 		free(filenames[i].name);
   521 	}
   522 
   523 	count = roots.size / sizeof (struct import_directory);
   524 	d = roots.data;
   525 	s = count;
   526 	for (i = 0; i < count; i++) {
   527 		count_entries(d);
   528 		if (i)
   529 			e = array_add(&importer->set->files, sizeof *e);
   530 		else
   531 			e = importer->set->files.data;
   532 		e->name = d->name;
   533 		e->flags = 0;
   534 		e->start = d->count > 0 ? s : 0;
   535 		s += d->count;
   536 		list_set_empty(&e->packages);
   537 		d++;
   538 	}
   539 	if (count)
   540 		e->flags |= RAZOR_ENTRY_LAST;
   541 
   542 	d = roots.data;
   543 	for (i = 0; i < count; i++) {
   544 		serialize_files(importer->set, d, &importer->set->files);
   545 		d++;
   546 	}
   547 
   548 	array_release(&importer->files);
   549 	array_release(&roots);
   550 }
   551 
   552 static void
   553 list_to_array(struct list *list, struct array *array)
   554 {
   555 	uint32_t *item;
   556 
   557 	while (list) {
   558 		 item = array_add(array, sizeof *item);
   559 		 *item = list->data;
   560 		 list = list_next(list);
   561 	}
   562 }
   563 
   564 static int
   565 compare_file_requires(const void *p1, const void *p2, void *data)
   566 {
   567 	uint32_t *f1 = (void *)p1, *f2 = (void *)p2;
   568 	const char *pool = data;
   569 
   570 	return strcmp(&pool[*f1], &pool[*f2]);
   571 }
   572 
   573 static void
   574 find_file_provides(struct razor_importer *importer)
   575 {
   576 	struct razor_property *prop;
   577 	struct razor_entry *top, *entry;
   578 	struct razor_package *packages;
   579 	struct array pkgprops;
   580 	struct list *pkg;
   581 	uint32_t *req, *req_start, *req_end;
   582 	uint32_t *map, *newprop;
   583 	char *pool;
   584 
   585 	pool = importer->set->string_pool.data;
   586 	packages = importer->set->packages.data;
   587 	top = importer->set->files.data;
   588 
   589 	req = req_start = importer->file_requires.data;
   590 	req_end = importer->file_requires.data + importer->file_requires.size;
   591 	map = razor_qsort_with_data(req, req_end - req, sizeof *req,
   592 				    compare_file_requires, pool);
   593 	free(map);
   594 
   595 	for (req = req_start; req < req_end; req++) {
   596 		if (req > req_start && req[0] == req[-1])
   597 			continue;
   598 		entry = razor_set_find_entry(importer->set, top, &pool[*req]);
   599 		if (!entry)
   600 			continue;
   601 
   602 		for (pkg = list_first(&entry->packages, &importer->set->package_pool); pkg; pkg = list_next(pkg)) {
   603 			prop = array_add(&importer->set->properties, sizeof *prop);
   604 			prop->name = *req;
   605 			prop->flags =
   606 				RAZOR_PROPERTY_PROVIDES | RAZOR_PROPERTY_EQUAL;
   607 			prop->version = hashtable_tokenize(&importer->table, "");
   608 			list_set_ptr(&prop->packages, pkg->data);
   609 
   610 			/* Update property list of pkg */
   611 			array_init(&pkgprops);
   612 			list_to_array(list_first(&packages[pkg->data].properties, &importer->set->property_pool), &pkgprops);
   613 			newprop = array_add(&pkgprops, sizeof *newprop);
   614 			*newprop = prop - (struct razor_property *)importer->set->properties.data;
   615 			list_set_array(&packages[pkg->data].properties, &importer->set->property_pool, &pkgprops, 1);
   616 			array_release(&pkgprops);
   617 		}
   618 	}
   619 
   620 	array_release(&importer->file_requires);
   621 }
   622 
   623 static void
   624 build_package_file_lists(struct razor_set *set, uint32_t *rmap)
   625 {
   626 	struct razor_package *p, *packages;
   627 	struct array *pkgs;
   628 	struct razor_entry *e, *end;
   629 	struct list *r;
   630 	uint32_t *q;
   631 	int i, count;
   632 
   633 	count = set->packages.size / sizeof *p;
   634 	pkgs = zalloc(count * sizeof *pkgs);
   635 
   636 	end = set->files.data + set->files.size;
   637 	for (e = set->files.data; e < end; e++) {
   638 		list_remap_head(&e->packages, rmap);
   639 		r = list_first(&e->packages, &set->package_pool);
   640 		while (r) {
   641 			q = array_add(&pkgs[r->data], sizeof *q);
   642 			*q = e - (struct razor_entry *) set->files.data;
   643 			r = list_next(r);
   644 		}
   645 	}
   646 
   647 	packages = set->packages.data;
   648 	for (i = 0; i < count; i++) {
   649 		list_set_array(&packages[i].files, &set->file_pool, &pkgs[i], 0);
   650 		array_release(&pkgs[i]);
   651 	}
   652 	free(pkgs);
   653 }
   654 
   655 /**
   656  * razor_importer_finish:
   657  * @importer: the %razor_importer
   658  *
   659  * Finish importing packages and create the package set.  This sorts
   660  * and indexes all the packages, properties and files in the importer
   661  * and creates a new %razor_set.  After creating the new package set,
   662  * the importer is destroyed.
   663  *
   664  * Returns: the new %razor_set
   665  **/
   666 RAZOR_EXPORT struct razor_set *
   667 razor_importer_finish(struct razor_importer *importer)
   668 {
   669 	struct razor_set *set;
   670 	uint32_t *map, *rmap;
   671 	int i, count;
   672 
   673 	build_file_tree(importer);
   674 	find_file_provides(importer);
   675 
   676 	map = uniqueify_properties(importer->set);
   677 	list_remap_pool(&importer->set->property_pool, map);
   678 	free(map);
   679 
   680 	count = importer->set->packages.size / sizeof(struct razor_package);
   681 	map = razor_qsort_with_data(importer->set->packages.data,
   682 				    count,
   683 				    sizeof(struct razor_package),
   684 				    compare_packages,
   685 				    importer->set);
   686 
   687 	rmap = malloc(count * sizeof *rmap);
   688 	for (i = 0; i < count; i++)
   689 		rmap[map[i]] = i;
   690 	free(map);
   691 
   692 	list_remap_pool(&importer->set->package_pool, rmap);
   693 	build_package_file_lists(importer->set, rmap);
   694 	remap_property_package_links(&importer->set->properties, rmap);
   695 	free(rmap);
   696 
   697 	set = importer->set;
   698 	hashtable_release(&importer->table);
   699 	hashtable_release(&importer->details_table);
   700 	hashtable_release(&importer->file_table);
   701 	free(importer);
   702 
   703 	return set;
   704 }