Add support for named roots so that we can understand MS-Windows paths
authorJ. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 22 15:09:17 2009 +0100 (2009-04-22)
changeset 359c9c90315ea24
parent 358 13beaca8b75f
child 360 c798d6db076b
Add support for named roots so that we can understand MS-Windows paths
such as c:/windows. Without this, the user always has to ensure they
are on the correct drive before running razor.
librazor/importer.c
librazor/merger.c
librazor/razor.c
librazor/razor.h
librazor/rpm.c
librazor/util.c
src/main.c
test/Makefile.am
test/named-root.sh
     1.1 --- a/librazor/importer.c	Fri Apr 17 23:08:11 2009 +0100
     1.2 +++ b/librazor/importer.c	Wed Apr 22 15:09:17 2009 +0100
     1.3 @@ -367,48 +367,56 @@
     1.4  	int count, i, length;
     1.5  	struct import_entry *filenames;
     1.6  	char *f, *end;
     1.7 -	uint32_t name, *r;
     1.8 -	char dirname[256];
     1.9 -	struct import_directory *d, root;
    1.10 +	uint32_t name, *r, s;
    1.11 +	char rootname[256], dirname[256];
    1.12 +	struct import_directory *d, *last_root;
    1.13 +	struct array roots;
    1.14  	struct razor_entry *e;
    1.15  
    1.16  	count = importer->files.size / sizeof (struct import_entry);
    1.17 -	razor_qsort_with_data(importer->files.data,
    1.18 +	filenames = importer->files.data;
    1.19 +	razor_qsort_with_data(filenames,
    1.20  			      count,
    1.21  			      sizeof (struct import_entry),
    1.22  			      compare_filenames,
    1.23  			      NULL);
    1.24  
    1.25 -	root.name = hashtable_tokenize(&importer->file_table, "");
    1.26 -	array_init(&root.files);
    1.27 -	array_init(&root.packages);
    1.28 -	root.last = NULL;
    1.29 +	array_init(&roots);
    1.30 +	last_root = NULL;
    1.31  
    1.32 -	filenames = importer->files.data;
    1.33  	for (i = 0; i < count; i++) {
    1.34  		f = filenames[i].name;
    1.35 -		if (*f != '/')
    1.36 -			continue;
    1.37 -		f++;
    1.38 -
    1.39 -		d = &root;
    1.40 +		d = NULL;
    1.41  		while (*f) {
    1.42  			end = strchr(f, '/');
    1.43  			if (end == NULL)
    1.44  				end = f + strlen(f);
    1.45  			length = end - f;
    1.46  			memcpy(dirname, f, length);
    1.47 -			dirname[length] ='\0';
    1.48 +			dirname[length] = '\0';
    1.49  			name = hashtable_tokenize(&importer->file_table,
    1.50  						  dirname);
    1.51 -			if (d->last == NULL || d->last->name != name) {
    1.52 -				d->last = array_add(&d->files, sizeof *d);
    1.53 -				d->last->name = name;
    1.54 -				d->last->last = NULL;
    1.55 -				array_init(&d->last->files);
    1.56 -				array_init(&d->last->packages);
    1.57 +			if (!d) {
    1.58 +				if (!last_root || last_root->name != name) {
    1.59 +					d = array_add(&roots, sizeof *d);
    1.60 +					d->name = name;
    1.61 +					d->last = NULL;
    1.62 +					array_init(&d->files);
    1.63 +					array_init(&d->packages);
    1.64 +					last_root = d;
    1.65 +				}
    1.66 +				d = last_root;
    1.67 +			} else {
    1.68 +				if (!d->last || d->last->name != name) {
    1.69 +					d->last = array_add(&d->files,
    1.70 +							    sizeof *d);
    1.71 +					d->last->name = name;
    1.72 +					d->last->last = NULL;
    1.73 +					array_init(&d->last->files);
    1.74 +					array_init(&d->last->packages);
    1.75 +				}
    1.76 +				d = d->last;
    1.77  			}
    1.78 -			d = d->last;
    1.79  			f = end + 1;
    1.80  			if (*end == '\0')
    1.81  				break;
    1.82 @@ -419,16 +427,33 @@
    1.83  		free(filenames[i].name);
    1.84  	}
    1.85  
    1.86 -	count_entries(&root);
    1.87 -	e = importer->set->files.data;
    1.88 -	e->name = root.name;
    1.89 -	e->flags = RAZOR_ENTRY_LAST;
    1.90 -	e->start = importer->files.size ? 1 : 0;
    1.91 -	list_set_empty(&e->packages);
    1.92 +	count = roots.size / sizeof (struct import_directory);
    1.93 +	d = roots.data;
    1.94 +	s = count;
    1.95 +	for (i = 0; i < count; i++) {
    1.96 +		count_entries(d);
    1.97 +		if (i)
    1.98 +			e = array_add(&importer->set->files, sizeof *e);
    1.99 +		else
   1.100 +			e = importer->set->files.data;
   1.101 +		e->name = d->name;
   1.102 +		e->flags = 0;
   1.103 +		e->start = d->count > 0 ? s : 0;
   1.104 +		s += d->count;
   1.105 +		list_set_empty(&e->packages);
   1.106 +		d++;
   1.107 +	}
   1.108 +	if (count)
   1.109 +		e->flags |= RAZOR_ENTRY_LAST;
   1.110  
   1.111 -	serialize_files(importer->set, &root, &importer->set->files);
   1.112 +	d = roots.data;
   1.113 +	for (i = 0; i < count; i++) {
   1.114 +		serialize_files(importer->set, d, &importer->set->files);
   1.115 +		d++;
   1.116 +	}
   1.117  
   1.118  	array_release(&importer->files);
   1.119 +	array_release(&roots);
   1.120  }
   1.121  
   1.122  static void
     2.1 --- a/librazor/merger.c	Fri Apr 17 23:08:11 2009 +0100
     2.2 +++ b/librazor/merger.c	Wed Apr 22 15:09:17 2009 +0100
     2.3 @@ -231,16 +231,15 @@
     2.4  	uint32_t e;
     2.5  	int found_file = 0;
     2.6  
     2.7 -	e = top->start;
     2.8 +	e = top - files;
     2.9  	do {
    2.10 -		if (files[e].start)
    2.11 -			fix_file_map(map, files, &files[e]);
    2.12 +		if (files[e].start &&
    2.13 +		    fix_file_map(map, files, &files[files[e].start]))
    2.14 +			map[e] = 1;
    2.15  		if (map[e])
    2.16  			found_file = 1;
    2.17  	} while (!(files[e++].flags & RAZOR_ENTRY_LAST));
    2.18  
    2.19 -	if (found_file)
    2.20 -		map[top - files] = 1;
    2.21  	return found_file;
    2.22  }
    2.23  
    2.24 @@ -271,9 +270,9 @@
    2.25  	array_init(&merge_stack);
    2.26  
    2.27  	start = merger->set->files.size / sizeof (struct razor_entry);
    2.28 -	last = 0;
    2.29 -	e1 = md->dir1 ? root1 + md->dir1 : NULL;
    2.30 -	e2 = md->dir2 ? root2 + md->dir2 : NULL;
    2.31 +	last = 0xFFFFFFFF;
    2.32 +	e1 = md->dir1 != 0xFFFFFFFF ? root1 + md->dir1 : NULL;
    2.33 +	e2 = md->dir2 != 0xFFFFFFFF ? root2 + md->dir2 : NULL;
    2.34  	while (e1 || e2) {
    2.35  		if (!e2 && !map1[e1 - root1]) {
    2.36  			if ((e1++)->flags & RAZOR_ENTRY_LAST)
    2.37 @@ -311,7 +310,7 @@
    2.38  					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
    2.39  					child_md->merged = last;
    2.40  					child_md->dir1 = e1->start;
    2.41 -					child_md->dir2 = 0;
    2.42 +					child_md->dir2 = 0xFFFFFFFF;
    2.43  				}
    2.44  			}
    2.45  			if ((e1++)->flags & RAZOR_ENTRY_LAST)
    2.46 @@ -323,7 +322,7 @@
    2.47  				if (e2->start) {
    2.48  					child_md = array_add(&merge_stack, sizeof (struct merge_directory));
    2.49  					child_md->merged = last;
    2.50 -					child_md->dir1 = 0;
    2.51 +					child_md->dir1 = 0xFFFFFFFF;
    2.52  					child_md->dir2 = e2->start;
    2.53  				}
    2.54  			}
    2.55 @@ -335,8 +334,8 @@
    2.56  			if (e1->start || e2->start) {
    2.57  				child_md = array_add(&merge_stack, sizeof (struct merge_directory));
    2.58  				child_md->merged = last;
    2.59 -				child_md->dir1 = e1->start;
    2.60 -				child_md->dir2 = e2->start;
    2.61 +				child_md->dir1 = e1->start ? e1->start : 0xFFFFFFFF;
    2.62 +				child_md->dir2 = e2->start ? e2->start : 0xFFFFFFFF;
    2.63  			}
    2.64  			if ((e1++)->flags & RAZOR_ENTRY_LAST)
    2.65  				e1 = NULL;
    2.66 @@ -346,11 +345,10 @@
    2.67  	}
    2.68  
    2.69  	mroot = (struct razor_entry *)merger->set->files.data;
    2.70 -	if (last) {
    2.71 +	if (last != 0xFFFFFFFF) {
    2.72  		mroot[last].flags = RAZOR_ENTRY_LAST;
    2.73  		mroot[md->merged].start = start;
    2.74 -	} else
    2.75 -		mroot[md->merged].start = 0;
    2.76 +	}
    2.77  
    2.78  	end_md = merge_stack.data + merge_stack.size;
    2.79  	for (child_md = merge_stack.data; child_md < end_md; child_md++)
    2.80 @@ -374,17 +372,23 @@
    2.81  		root = (struct razor_entry *) merger->source1.set->files.data;
    2.82  		if (root->start)
    2.83  			fix_file_map(map1, root, root);
    2.84 -		md.dir1 = root->start;
    2.85 -	} else
    2.86  		md.dir1 = 0;
    2.87 +	} else {
    2.88 +		md.dir1 = 0xFFFFFFFF;
    2.89 +	}
    2.90  
    2.91  	if (merger->source2.set->files.size) {
    2.92  		root = (struct razor_entry *) merger->source2.set->files.data;
    2.93  		if (root->start)
    2.94  			fix_file_map(map2, root, root);
    2.95 -		md.dir2 = root->start;
    2.96 -	} else
    2.97  		md.dir2 = 0;
    2.98 +	} else {
    2.99 +		md.dir2 = 0xFFFFFFFF;
   2.100 +	}
   2.101 +
   2.102 +	/* Remove the unnamed root which razor_set_create() added */
   2.103 +	array_release(&merger->set->files);
   2.104 +	array_init(&merger->set->files);
   2.105  
   2.106  	merge_one_directory(merger, &md);
   2.107  }
     3.1 --- a/librazor/razor.c	Fri Apr 17 23:08:11 2009 +0100
     3.2 +++ b/librazor/razor.c	Wed Apr 22 15:09:17 2009 +0100
     3.3 @@ -504,7 +504,7 @@
     3.4  razor_set_find_entry(struct razor_set *set,
     3.5  		     struct razor_entry *dir, const char *pattern)
     3.6  {
     3.7 -	struct razor_entry *e;
     3.8 +	struct razor_entry *e, *subdir;
     3.9  	const char *n, *pool = set->file_string_pool.data;
    3.10  	int len;
    3.11  
    3.12 @@ -512,15 +512,18 @@
    3.13  	assert (dir != NULL);
    3.14  	assert (pattern != NULL);
    3.15  
    3.16 -	e = (struct razor_entry *) set->files.data + dir->start;
    3.17 +	e = dir;
    3.18  	do {
    3.19  		n = pool + e->name;
    3.20 -		if (strcmp(pattern + 1, n) == 0)
    3.21 +		if (strcmp(pattern, n) == 0)
    3.22  			return e;
    3.23  		len = strlen(n);
    3.24 -		if (e->start != 0 && strncmp(pattern + 1, n, len) == 0 &&
    3.25 -		    pattern[len + 1] == '/') {
    3.26 -			return razor_set_find_entry(set, e, pattern + len + 1);
    3.27 +		if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
    3.28 +		    pattern[len] == '/') {
    3.29 +			subdir = (struct razor_entry *) set->files.data +
    3.30 +				 e->start;
    3.31 +			return razor_set_find_entry(set, subdir,
    3.32 +						    pattern + len + 1);
    3.33  		}
    3.34  	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
    3.35  
    3.36 @@ -531,10 +534,10 @@
    3.37  list_dir(struct razor_set *set, struct razor_entry *dir,
    3.38  	 char *prefix, const char *pattern)
    3.39  {
    3.40 -	struct razor_entry *e;
    3.41 +	struct razor_entry *e, *subdir;
    3.42  	const char *n, *pool = set->file_string_pool.data;
    3.43  
    3.44 -	e = (struct razor_entry *) set->files.data + dir->start;
    3.45 +	e = dir;
    3.46  	do {
    3.47  		n = pool + e->name;
    3.48  		if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
    3.49 @@ -544,7 +547,9 @@
    3.50  			char *sub = prefix + strlen (prefix);
    3.51  			*sub = '/';
    3.52  			strcpy (sub + 1, n);
    3.53 -			list_dir(set, e, prefix, pattern);
    3.54 +			subdir = (struct razor_entry *) set->files.data +
    3.55 +				 e->start;
    3.56 +			list_dir(set, subdir, prefix, pattern);
    3.57  			*sub = '\0';
    3.58  		}
    3.59  	} while (!((e++)->flags & RAZOR_ENTRY_LAST));
    3.60 @@ -553,20 +558,28 @@
    3.61  RAZOR_EXPORT void
    3.62  razor_set_list_files(struct razor_set *set, const char *pattern)
    3.63  {
    3.64 -	struct razor_entry *e;
    3.65 +	struct razor_entry *root, *e;
    3.66  	char buffer[512], *p, *base;
    3.67  
    3.68  	assert (set != NULL);
    3.69  
    3.70 -	if (pattern == NULL || !strcmp (pattern, "/")) {
    3.71 -		buffer[0] = '\0';
    3.72 -		list_dir(set, set->files.data, buffer, NULL);
    3.73 +	root = (struct razor_entry *) set->files.data;
    3.74 +
    3.75 +	if (pattern == NULL) {
    3.76 +		p = set->file_string_pool.data;
    3.77 +		e = root;
    3.78 +		do {
    3.79 +			if (e->start) {
    3.80 +				strcpy(buffer, p + e->name);
    3.81 +				list_dir(set, root + e->start, buffer, NULL);
    3.82 +			}
    3.83 +		} while (!((e++)->flags & RAZOR_ENTRY_LAST));
    3.84  		return;
    3.85  	}
    3.86  
    3.87  	strcpy(buffer, pattern);
    3.88 -	e = razor_set_find_entry(set, set->files.data, buffer);
    3.89 -	if (e && e->start > 0) {
    3.90 +	e = razor_set_find_entry(set, root, buffer);
    3.91 +	if (e && e->start) {
    3.92  		base = NULL;
    3.93  	} else {
    3.94  		p = strrchr(buffer, '/');
    3.95 @@ -577,9 +590,9 @@
    3.96  			base = NULL;
    3.97  		}
    3.98  	}
    3.99 -	e = razor_set_find_entry(set, set->files.data, buffer);
   3.100 -	if (e && e->start != 0)
   3.101 -		list_dir(set, e, buffer, base);
   3.102 +	e = razor_set_find_entry(set, root, buffer);
   3.103 +	if (e && e->start)
   3.104 +		list_dir(set, root + e->start, buffer, base);
   3.105  }
   3.106  
   3.107  RAZOR_EXPORT void
     4.1 --- a/librazor/razor.h	Fri Apr 17 23:08:11 2009 +0100
     4.2 +++ b/librazor/razor.h	Wed Apr 22 15:09:17 2009 +0100
     4.3 @@ -378,5 +378,7 @@
     4.4  		     const char *version, const char *release);
     4.5  int razor_versioncmp(const char *s1, const char *s2);
     4.6  
     4.7 +void razor_disable_root_name_checks(int disable);
     4.8 +
     4.9  
    4.10  #endif /* _RAZOR_H_ */
     5.1 --- a/librazor/rpm.c	Fri Apr 17 23:08:11 2009 +0100
     5.2 +++ b/librazor/rpm.c	Wed Apr 22 15:09:17 2009 +0100
     5.3 @@ -380,8 +380,6 @@
     5.4  
     5.5  RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr)
     5.6  {
     5.7 -	printf("razor_relocations_destroy(rr=%p): path=%p, rel=%p\n",
     5.8 -	  rr,rr->path,rr->relocations);
     5.9  	free(rr->path);
    5.10  	free(rr->relocations);
    5.11  	free(rr);
     6.1 --- a/librazor/util.c	Fri Apr 17 23:08:11 2009 +0100
     6.2 +++ b/librazor/util.c	Wed Apr 22 15:09:17 2009 +0100
     6.3 @@ -30,19 +30,49 @@
     6.4  #include <errno.h>
     6.5  #include <unistd.h>
     6.6  #include <fcntl.h>
     6.7 +#ifdef MSWIN_API
     6.8 +#include <direct.h>
     6.9 +#endif
    6.10  #if HAVE_SYS_MMAN_H
    6.11  #include <sys/mman.h>
    6.12  #endif
    6.13  
    6.14 +#include "razor.h"
    6.15  #include "razor-internal.h"
    6.16  
    6.17  #ifndef O_BINARY
    6.18  #define O_BINARY	0
    6.19  #endif
    6.20  
    6.21 +#define RAZOR_ASCII_ISALPHA(c)	\
    6.22 +			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
    6.23 +
    6.24  /* Required by gnulib on non-libc platforms */
    6.25  char *program_name = "librazor";
    6.26  
    6.27 +static int allow_all_root_names = 0;
    6.28 +
    6.29 +/*
    6.30 + * Primarily intended for testing named roots under UNIX platforms.
    6.31 + */
    6.32 +RAZOR_EXPORT void razor_disable_root_name_checks(int disable)
    6.33 +{
    6.34 +	allow_all_root_names = disable;
    6.35 +}
    6.36 +
    6.37 +static int razor_valid_root_name(const char *name)
    6.38 +{
    6.39 +	if (allow_all_root_names)
    6.40 +		return !strchr(name,'/');
    6.41 +
    6.42 +#ifdef MSWIN_API
    6.43 +	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
    6.44 +	       name[2] == '\0';
    6.45 +#else
    6.46 +	return name[0] == '\0';
    6.47 +#endif
    6.48 +}
    6.49 +
    6.50  int
    6.51  razor_create_dir(const char *root, const char *path)
    6.52  {
    6.53 @@ -51,8 +81,9 @@
    6.54  	struct stat buf;
    6.55  
    6.56  	/* Create all sub-directories in dir. We know root exists and
    6.57 -	 * is a dir, root does not end in a '/', and path has a
    6.58 -	 * leading '/'. */
    6.59 +	 * is a dir, root does not end in a '/', and path either has a
    6.60 +	 * leading '/' or (on MS-Windows only) root is the empty string
    6.61 +	 * and path starts with drive (eg., "c:/windows"). */
    6.62  
    6.63  	strcpy(buffer, root);
    6.64  	p = buffer + strlen(buffer);
    6.65 @@ -66,6 +97,9 @@
    6.66  		p += next - slash;
    6.67  		*p = '\0';
    6.68  
    6.69 +		if (razor_valid_root_name(buffer))
    6.70 +			continue;
    6.71 +
    6.72  		if (stat(buffer, &buf) == 0) {
    6.73  			if (!S_ISDIR(buf.st_mode)) {
    6.74  				fprintf(stderr,
     7.1 --- a/src/main.c	Fri Apr 17 23:08:11 2009 +0100
     7.2 +++ b/src/main.c	Wed Apr 22 15:09:17 2009 +0100
     7.3 @@ -1165,6 +1165,9 @@
     7.4  	if (yum_url == NULL)
     7.5  		yum_url = YUM_URL;
     7.6  
     7.7 +	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
     7.8 +		razor_disable_root_name_checks(1);
     7.9 +
    7.10  	if (argc < 2)
    7.11  		return usage();
    7.12  
     8.1 --- a/test/Makefile.am	Fri Apr 17 23:08:11 2009 +0100
     8.2 +++ b/test/Makefile.am	Wed Apr 22 15:09:17 2009 +0100
     8.3 @@ -1,6 +1,6 @@
     8.4  ## Process this file with automake to produce Makefile.in
     8.5  
     8.6 -check_SCRIPTS = relocate
     8.7 +check_SCRIPTS = relocate named-root
     8.8  if HAVE_LUA
     8.9    check_SCRIPTS += lua
    8.10  endif
    8.11 @@ -8,6 +8,9 @@
    8.12  relocate:	relocate.sh primary.xml.gz
    8.13  	cp $(srcdir)/relocate.sh relocate
    8.14  
    8.15 +named-root:	named-root.sh primary.xml.gz
    8.16 +	cp $(srcdir)/named-root.sh named-root
    8.17 +
    8.18  lua:	lua.sh primary.xml.gz
    8.19  	cp $(srcdir)/lua.sh lua
    8.20  
    8.21 @@ -32,6 +35,7 @@
    8.22  	zsh.spec		\
    8.23  	filesystem.spec		\
    8.24  	lua.sh			\
    8.25 +	named-root.sh		\
    8.26  	relocate.sh
    8.27  
    8.28  clean-local :
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/named-root.sh	Wed Apr 22 15:09:17 2009 +0100
     9.3 @@ -0,0 +1,53 @@
     9.4 +#!/bin/sh
     9.5 +check_file()
     9.6 +{
     9.7 +    ../src/razor list-files | grep -x "$1" > /dev/null
     9.8 +    if [ $? -ne 0 ]; then
     9.9 +	echo $1: Not in database >&2
    9.10 +	../src/razor list-files >&2
    9.11 +	exit 1
    9.12 +    fi
    9.13 +    ../src/razor list-files c: | grep -x "$1" > /dev/null
    9.14 +    if [ $? -ne 0 ]; then
    9.15 +	echo $1: Not seen by named root list >&2
    9.16 +	../src/razor list-files c: >&2
    9.17 +	exit 1
    9.18 +    fi
    9.19 +    ../src/razor list-files "$1" | grep -x "$1" > /dev/null
    9.20 +    if [ $? -ne 0 ]; then
    9.21 +	echo $1: Not seen by patterned list >&2
    9.22 +	../src/razor list-files "$1" >&2
    9.23 +	exit 1
    9.24 +    fi
    9.25 +    pkgs=`../src/razor list-file-packages "$1"`
    9.26 +    if [ -z "$pkgs" ]; then
    9.27 +	echo $1: Not owned by any package >&2
    9.28 +	../src/razor list-file-packages "$1"
    9.29 +	exit 1
    9.30 +    fi
    9.31 +    for nevra in "$pkgs"; do
    9.32 +	name=`echo $nevra | sed 's/\-.*$//'`
    9.33 +	../src/razor list-package-files "$name" | grep -x "$1" > /dev/null
    9.34 +	if [ $? -ne 0 ]; then
    9.35 +	    echo $1: Not in database for package $name >&2
    9.36 +	    ../src/razor list-package-files "$name"
    9.37 +	    exit 1
    9.38 +	fi
    9.39 +    done
    9.40 +    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    9.41 +	echo $1: Not in filesystem >&2
    9.42 +	exit 1
    9.43 +    fi
    9.44 +}
    9.45 +tmpdir=`mktemp -dt` || exit 1
    9.46 +export RAZOR_ROOT="$tmpdir/x-"
    9.47 +mkdir -p "$tmpdir/x-/var/lib" "$tmpdir/x-c:"
    9.48 +export RAZOR_NO_ROOT_NAME_CHECKS=1
    9.49 +../src/razor init || exit 1
    9.50 +export YUM_URL="file://localhost/`pwd`"
    9.51 +../src/razor import-yum || exit 1
    9.52 +../src/razor install --relocate /usr=c:/test zap || exit 1
    9.53 +../src/razor install --relocate /usr=c:/test zip || exit 1
    9.54 +check_file c:/test/bin/zap
    9.55 +check_file c:/test/bin/zip
    9.56 +rm -rf "$tmpdir"