Support getting file contents from archives
authorJ. Ali Harlow <ali@juiblex.co.uk>
Mon Jul 04 13:04:19 2016 +0100 (2016-07-04)
changeset 47648e45439fd9a
parent 475 008c75a5e08d
child 477 6ba4c0f3c9d1
Support getting file contents from archives
configure.ac
librazor/Makefile.am
librazor/razor-internal.h
librazor/razor.h.in
librazor/uri-io.c
src/Makefile.am
src/import-rpmdb.c
src/import-yum.c
src/import.h
src/main.c
test/Makefile.am
test/archive.sh
test/curl.sh
test/tftpd.c
     1.1 --- a/configure.ac	Mon Jul 04 10:48:18 2016 +0100
     1.2 +++ b/configure.ac	Mon Jul 04 13:04:19 2016 +0100
     1.3 @@ -205,6 +205,25 @@
     1.4  AC_MSG_RESULT($have_gcc4)
     1.5  
     1.6  REQUIREMENTS=""
     1.7 +AC_ARG_WITH([libarchive],
     1.8 +            [AS_HELP_STRING([--without-libarchive],
     1.9 +	        [disable support for libarchive])],
    1.10 +            [],
    1.11 +            [with_libarchive=yes])
    1.12 +          
    1.13 +LIBARCHIVE_CFLAGS=
    1.14 +LIBARCHIVE_LIBS=
    1.15 +AS_IF([test "x$with_libarchive" != xno],
    1.16 +  [PKG_CHECK_MODULES(LIBARCHIVE, [libarchive])
    1.17 +   REQUIREMENTS="$REQUIREMENTS libarchive"
    1.18 +   AC_DEFINE([HAVE_LIBARCHIVE], [1], [Define if you have libarchive])])
    1.19 +AC_SUBST(LIBARCHIVE_CFLAGS)
    1.20 +AC_SUBST(LIBARCHIVE_LIBS)
    1.21 +
    1.22 +AS_IF([test "x$with_libarchive" != xno],
    1.23 +   [AC_PATH_PROG(ZIP, [zip], [])])
    1.24 +AM_CONDITIONAL([HAVE_ZIP], [test -n "$ZIP"])
    1.25 +
    1.26  AC_ARG_WITH([curl],
    1.27              [AS_HELP_STRING([--without-curl], [disable support for curl])],
    1.28              [],
    1.29 @@ -217,6 +236,7 @@
    1.30     AC_DEFINE([HAVE_CURL], [1], [Define if you have curl])])
    1.31  AC_SUBST(CURL_CFLAGS)
    1.32  AC_SUBST(CURL_LIBS)
    1.33 +AM_CONDITIONAL([HAVE_CURL], [test "x$with_curl" != xno])
    1.34  
    1.35  ZLIB_LIBS=""
    1.36  AC_ARG_WITH(zlib, [  --with-zlib=<dir>       Use zlib from here],
     2.1 --- a/librazor/Makefile.am	Mon Jul 04 10:48:18 2016 +0100
     2.2 +++ b/librazor/Makefile.am	Mon Jul 04 13:04:19 2016 +0100
     2.3 @@ -55,8 +55,8 @@
     2.4    librazor_la_SOURCES += lua.c
     2.5  endif
     2.6  
     2.7 -librazor_la_LIBADD = $(ZLIB_LIBS) types/libtypes.la $(LUA_LIBS) \
     2.8 -	../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
     2.9 +librazor_la_LIBADD = $(LIBARCHIVE_LIBS) $(ZLIB_LIBS) types/libtypes.la \
    2.10 +	$(LUA_LIBS) ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
    2.11  librazor_la_LDFLAGS = -no-undefined -export-symbols-regex '^razor_' \
    2.12  	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
    2.13  
    2.14 @@ -76,7 +76,8 @@
    2.15  if HAVE_LUA
    2.16    test_lua_SOURCES = test-lua.c
    2.17    test_lua_LDADD = lua.lo uri.lo uri-io.lo util.lo path.lo error.lo \
    2.18 -  	types/libtypes.la $(LUA_LIBS) ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
    2.19 +  	types/libtypes.la $(LIBARCHIVE_LIBS) $(LUA_LIBS) ../gl/libgnu.la \
    2.20 +	$(INTLLIBS) $(EXTRA_LIBS)
    2.21  
    2.22    TESTS += test-lua
    2.23  endif
     3.1 --- a/librazor/razor-internal.h	Mon Jul 04 10:48:18 2016 +0100
     3.2 +++ b/librazor/razor-internal.h	Mon Jul 04 13:04:19 2016 +0100
     3.3 @@ -257,22 +257,6 @@
     3.4  char *razor_file_readdir(void *dir, struct razor_error **error);
     3.5  int razor_file_closedir(void *dir, struct razor_error **error);
     3.6  
     3.7 -int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error);
     3.8 -int razor_uri_unlink(const char *uri, struct razor_error **error);
     3.9 -int razor_uri_open(const char *uri, int flags, mode_t mode,
    3.10 -		   struct razor_error **error);
    3.11 -int razor_uri_move(const char *uri, const char *dest,
    3.12 -		   struct razor_error **error);
    3.13 -int razor_uri_is_directory(const char *uri, struct razor_error **error);
    3.14 -char *razor_uri_mkdtemp_near(const char *uri, const char *template,
    3.15 -			     struct razor_error **error) RAZOR_MALLOC;
    3.16 -void *razor_uri_opendir(const char *uri, struct razor_error **error);
    3.17 -char *razor_uri_readdir(void *dir, struct razor_error **error) RAZOR_MALLOC;
    3.18 -int razor_uri_closedir(void *dir, struct razor_error **error);
    3.19 -void *razor_uri_get_contents(const char *uri, size_t *length, int private,
    3.20 -			     struct razor_error **error);
    3.21 -int razor_uri_free_contents(void *addr, size_t length);
    3.22 -
    3.23  char *razor_path_from_parsed_uri(const struct razor_uri *ru,
    3.24    struct razor_error **error);
    3.25  
     4.1 --- a/librazor/razor.h.in	Mon Jul 04 10:48:18 2016 +0100
     4.2 +++ b/librazor/razor.h.in	Mon Jul 04 13:04:19 2016 +0100
     4.3 @@ -592,9 +592,6 @@
     4.4  
     4.5  struct razor_set *razor_importer_finish(struct razor_importer *importer);
     4.6  
     4.7 -struct razor_set *razor_set_create_from_yum(void);
     4.8 -struct razor_set *razor_set_create_from_rpmdb(void);
     4.9 -
    4.10  /**
    4.11   * SECTION:root
    4.12   * @title: Root
    4.13 @@ -650,6 +647,22 @@
    4.14  	int (*closedir)(void *dir, struct razor_error **error);
    4.15  };
    4.16  
    4.17 +int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error);
    4.18 +int razor_uri_unlink(const char *uri, struct razor_error **error);
    4.19 +int razor_uri_open(const char *uri, int flags, mode_t mode,
    4.20 +		   struct razor_error **error);
    4.21 +int razor_uri_move(const char *uri, const char *dest,
    4.22 +		   struct razor_error **error);
    4.23 +int razor_uri_is_directory(const char *uri, struct razor_error **error);
    4.24 +char *razor_uri_mkdtemp_near(const char *uri, const char *_template,
    4.25 +			     struct razor_error **error) RAZOR_MALLOC;
    4.26 +void *razor_uri_opendir(const char *uri, struct razor_error **error);
    4.27 +char *razor_uri_readdir(void *dir, struct razor_error **error) RAZOR_MALLOC;
    4.28 +int razor_uri_closedir(void *dir, struct razor_error **error);
    4.29 +void *razor_uri_get_contents(const char *uri, size_t *length, int _private,
    4.30 +			     struct razor_error **error);
    4.31 +int razor_uri_free_contents(void *addr, size_t length);
    4.32 +
    4.33  int razor_uri_set_vtable(const char *scheme, struct razor_uri_vtable *vtable,
    4.34  			 struct razor_error **error);
    4.35  
    4.36 @@ -680,7 +693,7 @@
    4.37  char *razor_path_from_uri(const char *uri, struct razor_error **error)
    4.38        RAZOR_MALLOC;
    4.39  char *razor_path_to_uri(const char *path) RAZOR_MALLOC;
    4.40 -char *razor_path_relative_to_uri(const char *file_uri, const char *path,
    4.41 +char *razor_path_relative_to_uri(const char *uri, const char *path,
    4.42  				 struct razor_error **error) RAZOR_MALLOC;
    4.43  
    4.44  const char *razor_system_arch(void);
     5.1 --- a/librazor/uri-io.c	Mon Jul 04 10:48:18 2016 +0100
     5.2 +++ b/librazor/uri-io.c	Mon Jul 04 13:04:19 2016 +0100
     5.3 @@ -38,6 +38,10 @@
     5.4  #if HAVE_SYS_MMAN_H
     5.5  #include <sys/mman.h>
     5.6  #endif
     5.7 +#if HAVE_LIBARCHIVE
     5.8 +#include <archive.h>
     5.9 +#include <archive_entry.h>
    5.10 +#endif
    5.11  #include <assert.h>
    5.12  
    5.13  #include "razor.h"
    5.14 @@ -51,6 +55,130 @@
    5.15  #define strcmp0(s1, s2)		((s1) && (s2) ? strcmp(s1, s2) : \
    5.16  				 (s1) ? 1 : (s2) ? -1 : 0)
    5.17  
    5.18 +#if HAVE_LIBARCHIVE
    5.19 +static void *
    5.20 +razor_archive_get_file_contents(const char *filename, int fd, const char *path,
    5.21 +				size_t *length, struct razor_error **error)
    5.22 +{
    5.23 +	int r;
    5.24 +	void *addr;
    5.25 +	const void *buf;
    5.26 +	size_t size;
    5.27 +	off_t offset;
    5.28 +	struct archive *a;
    5.29 +	struct archive_entry *entry;
    5.30 +
    5.31 +	a = archive_read_new();
    5.32 +	archive_read_support_compression_all(a);
    5.33 +	archive_read_support_format_all(a);
    5.34 +
    5.35 +	r = archive_read_open_fd(a, fd, 10240);
    5.36 +
    5.37 +	if (r) {
    5.38 +		razor_set_error(error, RAZOR_POSIX_ERROR, archive_errno(a),
    5.39 +				filename, archive_error_string(a));
    5.40 +		archive_read_finish(a);
    5.41 +		return NULL;
    5.42 +	}
    5.43 +
    5.44 +	for (;;) {
    5.45 +		r = archive_read_next_header(a, &entry);
    5.46 +		if (r == ARCHIVE_EOF)
    5.47 +			break;
    5.48 +		else if (r < ARCHIVE_WARN) {
    5.49 +			razor_set_error(error, RAZOR_POSIX_ERROR,
    5.50 +					archive_errno(a), filename,
    5.51 +					archive_error_string(a));
    5.52 +			archive_read_close(a);
    5.53 +			archive_read_finish(a);
    5.54 +			return NULL;
    5.55 +		}
    5.56 +
    5.57 +		/*
    5.58 +		 * TODO: Unicode support. Might need to wait for libarchive v4.
    5.59 +		 */
    5.60 +		if (!strcmp(archive_entry_pathname(entry), path)) {
    5.61 +			addr = malloc(archive_entry_size(entry));
    5.62 +			if (!addr) {
    5.63 +				archive_read_close(a);
    5.64 +				archive_read_finish(a);
    5.65 +				razor_set_error(error, RAZOR_POSIX_ERROR,
    5.66 +						ENOMEM, NULL,
    5.67 +						"Not enough memory");
    5.68 +				return NULL;
    5.69 +			}
    5.70 +
    5.71 +			for(;;) {
    5.72 +				r = archive_read_data_block(a, &buf, &size,
    5.73 +							    &offset);
    5.74 +				if (r == ARCHIVE_EOF)
    5.75 +					break;
    5.76 +				if (r < ARCHIVE_OK) {
    5.77 +					razor_set_error(error, RAZOR_POSIX_ERROR,
    5.78 +							archive_errno(a), path,
    5.79 +							archive_error_string(a));
    5.80 +					free(addr);
    5.81 +					addr = NULL;
    5.82 +					break;
    5.83 +				}
    5.84 +				memcpy((char *)addr + offset, buf, size);
    5.85 +			}
    5.86 +
    5.87 +			archive_read_close(a);
    5.88 +			archive_read_finish(a);
    5.89 +
    5.90 +			return addr;
    5.91 +		}
    5.92 +	}
    5.93 +
    5.94 +	archive_read_close(a);
    5.95 +	archive_read_finish(a);
    5.96 +
    5.97 +	razor_set_error(error, RAZOR_POSIX_ERROR, ENOENT, path,
    5.98 +			"No such file or directory in archive");
    5.99 +
   5.100 +	return NULL;
   5.101 +}
   5.102 +
   5.103 +static void *
   5.104 +razor_file_get_contents_archive(const char *filename, size_t *length,
   5.105 +				struct razor_error **error)
   5.106 +{
   5.107 +	int fd;
   5.108 +	char *path, *slash, *s;
   5.109 +	void *addr;
   5.110 +
   5.111 +	path = strdup(filename);
   5.112 +	slash = strrchr(path, '/');
   5.113 +
   5.114 +	while (slash) {
   5.115 +		*slash = '\0';
   5.116 +		fd = open(path, O_RDONLY | O_BINARY);
   5.117 +		if (fd >= 0) {
   5.118 +			addr = razor_archive_get_file_contents(path, fd,
   5.119 +							       slash + 1,
   5.120 +							       length, error);
   5.121 +			free(path);
   5.122 +			close(fd);
   5.123 +			return addr;
   5.124 +		} else if (errno != ENOTDIR) {
   5.125 +			free(path);
   5.126 +			razor_set_error_posix(error, filename);
   5.127 +			return NULL;
   5.128 +		}
   5.129 +		s = strrchr(path, '/');
   5.130 +		*slash = '/';
   5.131 +		slash = s;
   5.132 +	}
   5.133 +
   5.134 +	/* Impossible */
   5.135 +	free(path);
   5.136 +	razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, filename,
   5.137 +			strerror(ENOTDIR));
   5.138 +	return NULL;
   5.139 +}
   5.140 +#endif
   5.141 +
   5.142  #define OPEN_FILE_USED		(1U<<0)
   5.143  #define OPEN_FILE_MMAPPED	(1U<<1)
   5.144  
   5.145 @@ -68,24 +196,33 @@
   5.146  	int fd;
   5.147  	struct stat st;
   5.148  	void *addr = NULL;
   5.149 -	size_t nb;
   5.150 +	size_t nb, size;
   5.151  	ssize_t res;
   5.152  	struct open_file *of, *ofend;
   5.153  
   5.154  	fd = open(filename, O_RDONLY | O_BINARY);
   5.155  	if (fd < 0) {
   5.156 +#if HAVE_LIBARCHIVE
   5.157 +		if (errno != ENOTDIR) {
   5.158 +			razor_set_error_posix(error, filename);
   5.159 +			return NULL;
   5.160 +		}
   5.161 +		addr = razor_file_get_contents_archive(filename, &size, error);
   5.162 +		if (!addr)
   5.163 +			return NULL;
   5.164 +#else
   5.165  		razor_set_error_posix(error, filename);
   5.166  		return NULL;
   5.167 +#endif
   5.168 +	} else {
   5.169 +		if (fstat(fd, &st) < 0) {
   5.170 +			razor_set_error_posix(error, filename);
   5.171 +			close(fd);
   5.172 +			return NULL;
   5.173 +		}
   5.174 +		size = st.st_size;
   5.175  	}
   5.176  
   5.177 -	if (fstat(fd, &st) < 0) {
   5.178 -		razor_set_error_posix(error, filename);
   5.179 -		close(fd);
   5.180 -		return NULL;
   5.181 -	}
   5.182 -
   5.183 -	*length = st.st_size;
   5.184 -
   5.185  	ofend = open_files.data + open_files.size;
   5.186  	for (of = open_files.data; of < ofend; of++)
   5.187  		if (!(of->flags & OPEN_FILE_USED))
   5.188 @@ -96,21 +233,21 @@
   5.189  	}
   5.190  
   5.191  #if HAVE_SYS_MMAN_H
   5.192 -	if (!private) {
   5.193 -		addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   5.194 +	if (!addr && !private) {
   5.195 +		addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
   5.196  		if (addr == MAP_FAILED)
   5.197  			addr = NULL;
   5.198  		else
   5.199  			of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED;
   5.200  	}
   5.201  #endif	/* HAVE_SYS_MMAN_H */
   5.202 +
   5.203  	if (!addr) {
   5.204 -		addr = malloc(st.st_size);
   5.205 +		addr = malloc(size);
   5.206  		if (addr) {
   5.207 -			of->flags = OPEN_FILE_USED;
   5.208  			nb = 0;
   5.209 -			while(nb < st.st_size) {
   5.210 -				res = read(fd, addr + nb, st.st_size - nb);
   5.211 +			while(nb < size) {
   5.212 +				res = read(fd, addr + nb, size - nb);
   5.213  				if (res <= 0) {
   5.214  					razor_set_error_posix(error, filename);
   5.215  					free(addr);
   5.216 @@ -119,14 +256,21 @@
   5.217  				}
   5.218  				nb += res;
   5.219  			}
   5.220 +			if (addr)
   5.221 +				of->flags = OPEN_FILE_USED;
   5.222  		} else
   5.223  			razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   5.224  					"Not enough memory");
   5.225  	}
   5.226 -	close(fd);
   5.227 +
   5.228 +	if (fd >= 0)
   5.229 +		close(fd);
   5.230  
   5.231  	of->addr = addr;
   5.232 -	of->length = st.st_size;
   5.233 +	of->length = size;
   5.234 +
   5.235 +	if (addr)
   5.236 +		*length = size;
   5.237  
   5.238  	return addr;
   5.239  }
   5.240 @@ -659,7 +803,8 @@
   5.241  	return fallback;
   5.242  }
   5.243  
   5.244 -int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error)
   5.245 +RAZOR_EXPORT int
   5.246 +razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error)
   5.247  {
   5.248  	int retval;
   5.249  	char *path;
   5.250 @@ -700,7 +845,8 @@
   5.251  	return retval;
   5.252  }
   5.253  
   5.254 -int razor_uri_unlink(const char *uri, struct razor_error **error)
   5.255 +RAZOR_EXPORT int
   5.256 +razor_uri_unlink(const char *uri, struct razor_error **error)
   5.257  {
   5.258  	int retval;
   5.259  	char *path;
   5.260 @@ -741,8 +887,9 @@
   5.261  	return retval;
   5.262  }
   5.263  
   5.264 -int razor_uri_open(const char *uri, int flags, mode_t mode,
   5.265 -		   struct razor_error **error)
   5.266 +RAZOR_EXPORT int
   5.267 +razor_uri_open(const char *uri, int flags, mode_t mode,
   5.268 +	       struct razor_error **error)
   5.269  {
   5.270  	int retval;
   5.271  	char *path;
   5.272 @@ -783,8 +930,9 @@
   5.273  	return retval;
   5.274  }
   5.275  
   5.276 -int razor_uri_move(const char *src_uri, const char *dst_uri,
   5.277 -		   struct razor_error **error)
   5.278 +RAZOR_EXPORT int
   5.279 +razor_uri_move(const char *src_uri, const char *dst_uri,
   5.280 +	       struct razor_error **error)
   5.281  {
   5.282  	int retval;
   5.283  	char *src_path, *dst_path;
   5.284 @@ -851,8 +999,9 @@
   5.285  	return retval;
   5.286  }
   5.287  
   5.288 -void *razor_uri_get_contents(const char *uri, size_t *length, int private,
   5.289 -			     struct razor_error **error)
   5.290 +RAZOR_EXPORT void *
   5.291 +razor_uri_get_contents(const char *uri, size_t *length, int private,
   5.292 +		       struct razor_error **error)
   5.293  {
   5.294  	void *retval;
   5.295  	char *path;
   5.296 @@ -897,7 +1046,7 @@
   5.297  	return retval;
   5.298  }
   5.299  
   5.300 -int razor_uri_free_contents(void *addr, size_t length)
   5.301 +RAZOR_EXPORT int razor_uri_free_contents(void *addr, size_t length)
   5.302  {
   5.303  	int retval, of;
   5.304  	struct razor_uri_vtable_entry *entry, *eend;
   5.305 @@ -925,7 +1074,8 @@
   5.306  	return retval;
   5.307  }
   5.308  
   5.309 -int razor_uri_is_directory(const char *uri, struct razor_error **error)
   5.310 +RAZOR_EXPORT int
   5.311 +razor_uri_is_directory(const char *uri, struct razor_error **error)
   5.312  {
   5.313  	int retval;
   5.314  	char *path;
   5.315 @@ -966,8 +1116,9 @@
   5.316  	return retval;
   5.317  }
   5.318  
   5.319 -char *razor_uri_mkdtemp_near(const char *uri, const char *template,
   5.320 -			     struct razor_error **error)
   5.321 +RAZOR_EXPORT char *
   5.322 +razor_uri_mkdtemp_near(const char *uri, const char *template,
   5.323 +		       struct razor_error **error)
   5.324  {
   5.325  	char *retval, *s;
   5.326  	char *path;
   5.327 @@ -1011,7 +1162,8 @@
   5.328  	return retval;
   5.329  }
   5.330  
   5.331 -void *razor_uri_opendir(const char *uri, struct razor_error **error)
   5.332 +RAZOR_EXPORT void *
   5.333 +razor_uri_opendir(const char *uri, struct razor_error **error)
   5.334  {
   5.335  	void *retval;
   5.336  	char *path;
   5.337 @@ -1055,7 +1207,7 @@
   5.338  	return retval;
   5.339  }
   5.340  
   5.341 -char *razor_uri_readdir(void *dir, struct razor_error **error)
   5.342 +RAZOR_EXPORT char *razor_uri_readdir(void *dir, struct razor_error **error)
   5.343  {
   5.344  	int od;
   5.345  	char *retval;
   5.346 @@ -1086,7 +1238,7 @@
   5.347  	return retval;
   5.348  }
   5.349  
   5.350 -int razor_uri_closedir(void *dir, struct razor_error **error)
   5.351 +RAZOR_EXPORT int razor_uri_closedir(void *dir, struct razor_error **error)
   5.352  {
   5.353  	int od;
   5.354  	int retval;
     6.1 --- a/src/Makefile.am	Mon Jul 04 10:48:18 2016 +0100
     6.2 +++ b/src/Makefile.am	Mon Jul 04 13:04:19 2016 +0100
     6.3 @@ -24,7 +24,7 @@
     6.4    pkgdata_DATA = test.xml
     6.5  endif
     6.6  
     6.7 -razor_SOURCES = main.c import-yum.c
     6.8 +razor_SOURCES = main.c import.h import-yum.c
     6.9  if HAVE_RPMLIB
    6.10  razor_SOURCES += import-rpmdb.c
    6.11  endif
     7.1 --- a/src/import-rpmdb.c	Mon Jul 04 10:48:18 2016 +0100
     7.2 +++ b/src/import-rpmdb.c	Mon Jul 04 13:04:19 2016 +0100
     7.3 @@ -32,6 +32,7 @@
     7.4  #include <rpm/rpmdb.h>
     7.5  
     7.6  #include "razor.h"
     7.7 +#include "import.h"
     7.8  
     7.9  union rpm_entry {
    7.10  	void *p;
     8.1 --- a/src/import-yum.c	Mon Jul 04 10:48:18 2016 +0100
     8.2 +++ b/src/import-yum.c	Mon Jul 04 13:04:19 2016 +0100
     8.3 @@ -23,6 +23,7 @@
     8.4  #include <string.h>
     8.5  #include <stdio.h>
     8.6  #include <stdint.h>
     8.7 +#include <assert.h>
     8.8  #include <sys/stat.h>
     8.9  #include <unistd.h>
    8.10  #include <fcntl.h>
    8.11 @@ -31,6 +32,7 @@
    8.12  #include <expat.h>
    8.13  #include <zlib.h>
    8.14  #include "razor.h"
    8.15 +#include "import.h"
    8.16  
    8.17  /* Import a yum filelist as a razor package set. */
    8.18  
    8.19 @@ -282,14 +284,76 @@
    8.20  
    8.21  #define XML_BUFFER_SIZE 4096
    8.22  
    8.23 +struct razor_stream {
    8.24 +	z_stream strm;
    8.25 +	void *in;
    8.26 +	size_t in_length;
    8.27 +};
    8.28 +
    8.29 +static int razor_stream_open(struct razor_stream *rs, const char *uri,
    8.30 +			     struct razor_error **error)
    8.31 +{
    8.32 +	rs->strm.zalloc = Z_NULL;
    8.33 +	rs->strm.zfree = Z_NULL;
    8.34 +	rs->strm.opaque = Z_NULL;
    8.35 +	rs->strm.avail_in = 0;
    8.36 +	rs->strm.next_in = Z_NULL;
    8.37 +
    8.38 +	if (inflateInit2(&rs->strm, 15 + 16) != Z_OK) {
    8.39 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
    8.40 +				RAZOR_GENERAL_ERROR_FAILED, uri,
    8.41 +				"Failed to initialize inflator");
    8.42 +		return -1;
    8.43 +	}
    8.44 +
    8.45 +	rs->in = razor_uri_get_contents(uri, &rs->in_length, 0, error);
    8.46 +	if (!rs->in) {
    8.47 +		(void)inflateEnd(&rs->strm);
    8.48 +		return -1;
    8.49 +	}
    8.50 +
    8.51 +	rs->strm.avail_in = rs->in_length;
    8.52 +	rs->strm.next_in = rs->in;
    8.53 +
    8.54 +	return 0;
    8.55 +}
    8.56 +
    8.57 +static ssize_t
    8.58 +razor_stream_read(struct razor_stream *rs, unsigned char *buf, size_t len)
    8.59 +{
    8.60 +	int r;
    8.61 +
    8.62 +	rs->strm.avail_out = len;
    8.63 +	rs->strm.next_out = buf;
    8.64 +
    8.65 +	r = inflate(&rs->strm, Z_NO_FLUSH);
    8.66 +	assert(r != Z_STREAM_ERROR);  /* state not clobbered */
    8.67 +	switch (r) {
    8.68 +	case Z_NEED_DICT:
    8.69 +	case Z_DATA_ERROR:
    8.70 +	case Z_MEM_ERROR:
    8.71 +		return -1;
    8.72 +	}
    8.73 +
    8.74 +	return len - rs->strm.avail_out;
    8.75 +}
    8.76 +
    8.77 +static void razor_stream_close(struct razor_stream *rs)
    8.78 +{
    8.79 +	(void)inflateEnd(&rs->strm);
    8.80 +	(void)razor_uri_free_contents(rs->in, rs->in_length);
    8.81 +}
    8.82 +
    8.83  struct razor_set *
    8.84 -razor_set_create_from_yum(void)
    8.85 +razor_set_create_from_yum(const char *yum_uri)
    8.86  {
    8.87  	struct yum_context ctx={0};
    8.88 +	char *uri;
    8.89  	void *buf;
    8.90 -	int len;
    8.91 -	gzFile primary, filelists;
    8.92 +	ssize_t len;
    8.93  	XML_ParsingStatus status;
    8.94 +	struct razor_error *error = NULL;
    8.95 +	struct razor_stream primary, filelists;
    8.96  
    8.97  	ctx.importer = razor_importer_create();
    8.98  	ctx.state = YUM_STATE_BEGIN;
    8.99 @@ -310,16 +374,37 @@
   8.100  	XML_SetCharacterDataHandler(ctx.filelists_parser,
   8.101  				    yum_character_data);
   8.102  
   8.103 -	primary = gzopen("primary.xml.gz", "rb");
   8.104 -	if (primary == NULL) {
   8.105 -		perror("primary.xml.gz");
   8.106 +	uri = razor_path_relative_to_uri(yum_uri, "repodata/primary.xml.gz",
   8.107 +					 &error);
   8.108 +	if (!uri) {
   8.109 +		fprintf(stderr, "%s: %s\n", yum_uri,
   8.110 +			razor_error_get_msg(error));
   8.111 +		razor_error_free(error);
   8.112  		return NULL;
   8.113  	}
   8.114 -	filelists = gzopen("filelists.xml.gz", "rb");
   8.115 -	if (filelists == NULL) {
   8.116 -		perror("filelists.xml.gz");
   8.117 +	if (razor_stream_open(&primary, uri, &error)) {
   8.118 +		fprintf(stderr, "%s: %s\n", uri, razor_error_get_msg(error));
   8.119 +		free(uri);
   8.120  		return NULL;
   8.121  	}
   8.122 +	free(uri);
   8.123 +
   8.124 +	uri = razor_path_relative_to_uri(yum_uri, "repodata/filelists.xml.gz",
   8.125 +					 &error);
   8.126 +	if (!uri) {
   8.127 +		razor_stream_close(&primary);
   8.128 +		fprintf(stderr, "%s: %s\n", yum_uri,
   8.129 +			razor_error_get_msg(error));
   8.130 +		razor_error_free(error);
   8.131 +		return NULL;
   8.132 +	}
   8.133 +	if (razor_stream_open(&filelists, uri, &error)) {
   8.134 +		razor_stream_close(&primary);
   8.135 +		fprintf(stderr, "%s: %s\n", uri, razor_error_get_msg(error));
   8.136 +		free(uri);
   8.137 +		return NULL;
   8.138 +	}
   8.139 +	free(uri);
   8.140  
   8.141  	ctx.current_parser = ctx.primary_parser;
   8.142  
   8.143 @@ -336,9 +421,11 @@
   8.144  			buf = XML_GetBuffer(ctx.current_parser,
   8.145  					    XML_BUFFER_SIZE);
   8.146  			if (ctx.current_parser == ctx.primary_parser)
   8.147 -				len = gzread(primary, buf, XML_BUFFER_SIZE);
   8.148 +				len = razor_stream_read(&primary, buf,
   8.149 +							XML_BUFFER_SIZE);
   8.150  			else
   8.151 -				len = gzread(filelists, buf, XML_BUFFER_SIZE);
   8.152 +				len = razor_stream_read(&filelists, buf,
   8.153 +							XML_BUFFER_SIZE);
   8.154  			if (len < 0) {
   8.155  				fprintf(stderr,
   8.156  					"couldn't read input: %s\n",
   8.157 @@ -357,8 +444,8 @@
   8.158  	XML_ParserFree(ctx.primary_parser);
   8.159  	XML_ParserFree(ctx.filelists_parser);
   8.160  
   8.161 -	gzclose(primary);
   8.162 -	gzclose(filelists);
   8.163 +	razor_stream_close(&primary);
   8.164 +	razor_stream_close(&filelists);
   8.165  
   8.166  	printf ("\nsaving\n");
   8.167  	return razor_importer_finish(ctx.importer);
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/import.h	Mon Jul 04 13:04:19 2016 +0100
     9.3 @@ -0,0 +1,9 @@
     9.4 +#ifndef _RAZOR_IMPORT_H_
     9.5 +#define _RAZOR_IMPORT_H_
     9.6 +
     9.7 +#include "razor.h"
     9.8 +
     9.9 +struct razor_set *razor_set_create_from_yum(const char *yum_uri);
    9.10 +struct razor_set *razor_set_create_from_rpmdb(void);
    9.11 +
    9.12 +#endif /* _RAZOR_IMPORT_H_ */
    10.1 --- a/src/main.c	Mon Jul 04 10:48:18 2016 +0100
    10.2 +++ b/src/main.c	Mon Jul 04 13:04:19 2016 +0100
    10.3 @@ -46,6 +46,7 @@
    10.4  #include <errno.h>
    10.5  #include <getopt.h>
    10.6  #include "razor.h"
    10.7 +#include "import.h"
    10.8  
    10.9  static const char system_repo_filename[] = "system.rzdb";
   10.10  static const char next_repo_filename[] = "system-next.rzdb";
   10.11 @@ -614,140 +615,121 @@
   10.12  				      RAZOR_PROPERTY_PROVIDES);
   10.13  }
   10.14  
   10.15 -#ifndef HAVE_CURL
   10.16 -static int
   10.17 -download_local(const char *url, const char *file)
   10.18 +#ifdef HAVE_CURL
   10.19 +struct get_contents_with_curl_baton {
   10.20 +	void *buf;
   10.21 +	size_t buflen;
   10.22 +};
   10.23 +
   10.24 +static size_t
   10.25 +get_contents_with_curl_callback(void *contents, size_t size, size_t nmemb,
   10.26 +				void *data)
   10.27  {
   10.28 -	FILE *wfp, *rfp;
   10.29 -	char buffer[256], *ptr, *local;
   10.30 -	size_t nb, n;
   10.31 -	struct razor_error *error = NULL;
   10.32 +	size_t nb = size * nmemb;
   10.33 +	struct get_contents_with_curl_baton *baton = data;
   10.34  
   10.35 -	local = razor_path_from_uri(url, &error);
   10.36 -
   10.37 -	if (local == NULL) {
   10.38 -		fprintf(stderr, "%s: %s\n", file, razor_error_get_msg(error));
   10.39 -		razor_error_free(error);
   10.40 -		return -1;
   10.41 -	} else {
   10.42 -		rfp = fopen(local, "rb");
   10.43 -		if (rfp == NULL) {
   10.44 -			perror(local);
   10.45 -			free(local);
   10.46 -			return -1;
   10.47 -		}
   10.48 -
   10.49 -		wfp = fopen(file, "wb");
   10.50 -		if (wfp == NULL) {
   10.51 -			perror(file);
   10.52 -			fclose(rfp);
   10.53 -			free(local);
   10.54 -			return -1;
   10.55 -		}
   10.56 -
   10.57 -		while((nb = fread(buffer, 1, sizeof(buffer), rfp)) > 0) {
   10.58 -			ptr = buffer;
   10.59 -			while (nb > 0 && (n = fwrite(ptr, 1, nb, wfp)) > 0) {
   10.60 -				ptr += n;
   10.61 -				nb -= n;
   10.62 -			}
   10.63 -
   10.64 -			if (nb != 0) {
   10.65 -				perror(file);
   10.66 -				fclose(wfp);
   10.67 -				fclose(rfp);
   10.68 -				unlink(file);
   10.69 -				free(local);
   10.70 -				return -1;
   10.71 -			}
   10.72 -		}
   10.73 -
   10.74 -		if (ferror(rfp)) {
   10.75 -			perror(local);
   10.76 -			fclose(wfp);
   10.77 -			fclose(rfp);
   10.78 -			unlink(file);
   10.79 -			free(local);
   10.80 -			return -1;
   10.81 -		}
   10.82 -
   10.83 -		fclose(wfp);
   10.84 -		fclose(rfp);
   10.85 -		free(local);
   10.86 +	baton->buf = realloc(baton->buf, baton->buflen + nb);
   10.87 +	if (!baton->buf) {
   10.88 +		fprintf(stderr, "Not enough memory to read file\n");
   10.89  		return 0;
   10.90  	}
   10.91 +			 
   10.92 +	memcpy((char *)baton->buf + baton->buflen, contents, nb);
   10.93 +	baton->buflen += nb;
   10.94 +
   10.95 +	return nb;
   10.96  }
   10.97 -#endif /* !HAVE_CURL */
   10.98  
   10.99 +static void *get_contents_with_curl(const char *uri, size_t *length,
  10.100 +				    int private, struct razor_error **error)
  10.101 +{
  10.102 +	CURL *curl;
  10.103 +	char errbuf[256];
  10.104 +	CURLcode res;
  10.105 +	struct get_contents_with_curl_baton baton = {0,};
  10.106 +
  10.107 +	curl = curl_easy_init();
  10.108 +	if (!curl) {
  10.109 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  10.110 +				RAZOR_GENERAL_ERROR_FAILED, uri,
  10.111 +				"Failed to initialize libcurl");
  10.112 +		return NULL;
  10.113 +	}
  10.114 +
  10.115 +	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
  10.116 +	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
  10.117 +			 get_contents_with_curl_callback);
  10.118 +	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&baton);
  10.119 +	curl_easy_setopt(curl, CURLOPT_URL, uri);
  10.120 +	curl_easy_setopt(curl, CURLOPT_USERAGENT, "razor/" VERSION);
  10.121 +	res = curl_easy_perform(curl);
  10.122 +	curl_easy_cleanup(curl);
  10.123 +
  10.124 +	if (res != CURLE_OK) {
  10.125 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  10.126 +				RAZOR_GENERAL_ERROR_FAILED, uri, errbuf);
  10.127 +		free(baton.buf);
  10.128 +		return NULL;
  10.129 +	}
  10.130 +
  10.131 +	*length = baton.buflen;
  10.132 +	return baton.buf;
  10.133 +}
  10.134 +
  10.135 +int free_contents_with_curl(void *addr, size_t length)
  10.136 +{
  10.137 +	free(addr);
  10.138 +}
  10.139 +#endif
  10.140 +
  10.141 +void init_uri_handler(void)
  10.142 +{
  10.143  #ifdef HAVE_CURL
  10.144 -static int
  10.145 -show_progress(void *clientp,
  10.146 -	      double dltotal, double dlnow, double ultotal, double ulnow)
  10.147 -{
  10.148 -	const char *file = clientp;
  10.149 -
  10.150 -	if (!dlnow < dltotal)
  10.151 -		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
  10.152 -			file, (int) dlnow / 1024, (int) dltotal / 1024);
  10.153 -
  10.154 -	return 0;
  10.155 +	struct razor_uri_vtable uri_vtable={0,};
  10.156 +	uri_vtable.structure_size=sizeof(uri_vtable);
  10.157 +	uri_vtable.get_contents=get_contents_with_curl;
  10.158 +	uri_vtable.free_contents=free_contents_with_curl;
  10.159 +	razor_uri_set_vtable(NULL, &uri_vtable, NULL);
  10.160 +#endif
  10.161  }
  10.162  
  10.163  static int
  10.164 -download_with_curl(const char *url, const char *file)
  10.165 +download_if_missing(const char *uri, const char *file)
  10.166  {
  10.167 +	int retval = 0;
  10.168 +	struct stat buf;
  10.169 +	void *contents;
  10.170 +	size_t length;
  10.171 +	struct razor_error *error = NULL;
  10.172  	FILE *fp;
  10.173 -	CURL *curl;
  10.174 -	char error[256];
  10.175 -	CURLcode res;
  10.176 -	long response;
  10.177 -
  10.178 -	curl = curl_easy_init();
  10.179 -	if (curl == NULL) {
  10.180 -		fprintf(stderr,
  10.181 -			"%s: download manually (curl failed)\n", file);
  10.182 -		return -1;
  10.183 -	}
  10.184 -
  10.185 -	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
  10.186 -	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
  10.187 -	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
  10.188 -	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
  10.189 -
  10.190 -	fp = fopen(file, "wb");
  10.191 -	if (fp == NULL) {
  10.192 -		perror(file);
  10.193 -		return -1;
  10.194 -	}
  10.195 -	curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
  10.196 -	curl_easy_setopt(curl, CURLOPT_URL, url);
  10.197 -	res = curl_easy_perform(curl);
  10.198 -	fclose(fp);
  10.199 -	putc('\n', stderr);
  10.200 -	if (res != CURLE_OK) {
  10.201 -		fprintf(stderr, "curl error: %s\n", error);
  10.202 -		unlink(file);
  10.203 -		return -1;
  10.204 -	}
  10.205 -	curl_easy_cleanup(curl);
  10.206 -
  10.207 -	return 0;
  10.208 -}
  10.209 -#endif	/* HAVE_CURL */
  10.210 -
  10.211 -static int
  10.212 -download_if_missing(const char *url, const char *file)
  10.213 -{
  10.214 -	struct stat buf;
  10.215  
  10.216  	if (stat(file, &buf) >= 0)
  10.217  		return 0;
  10.218  
  10.219 -#ifndef HAVE_CURL
  10.220 -	return download_local(url, file);
  10.221 -#else
  10.222 -	return download_with_curl(url, file);
  10.223 -#endif
  10.224 +	contents = razor_uri_get_contents(uri, &length, 0, &error);
  10.225 +
  10.226 +	if (!contents) {
  10.227 +		fprintf(stderr, "%s: %s\n", uri, razor_error_get_msg(error));
  10.228 +		razor_error_free(error);
  10.229 +		return -1;
  10.230 +	}
  10.231 +
  10.232 +	fp = fopen(file, "wb");
  10.233 +	if (!fp) {
  10.234 +		perror(file);
  10.235 +		razor_uri_free_contents(contents, length);
  10.236 +		return -1;
  10.237 +	}
  10.238 +
  10.239 +	if (fwrite(contents, 1, length, fp) != length) {
  10.240 +		perror(file);
  10.241 +		retval = -1;
  10.242 +	}
  10.243 +
  10.244 +	fclose(fp);
  10.245 +	razor_uri_free_contents(contents, length);
  10.246 +
  10.247 +	return retval;
  10.248  }
  10.249  
  10.250  #define YUM_URL "http://download.fedora.redhat.com" \
  10.251 @@ -773,17 +755,9 @@
  10.252  		return 1;
  10.253  	}
  10.254  
  10.255 -	printf("downloading from '%s'.\n", yum_url);
  10.256 -	snprintf(buffer, sizeof buffer,
  10.257 -		 "%s/repodata/primary.xml.gz", yum_url);
  10.258 -	if (download_if_missing(buffer, "primary.xml.gz") < 0)
  10.259 -		return -1;
  10.260 -	snprintf(buffer, sizeof buffer,
  10.261 -		 "%s/repodata/filelists.xml.gz", yum_url);
  10.262 -	if (download_if_missing(buffer, "filelists.xml.gz") < 0)
  10.263 -		return -1;
  10.264 +	printf("importing from '%s'.\n", yum_url);
  10.265  
  10.266 -	set = razor_set_create_from_yum();
  10.267 +	set = razor_set_create_from_yum(yum_url);
  10.268  	if (set == NULL)
  10.269  		return 1;
  10.270  	atomic = razor_atomic_open("Yum import repository");
  10.271 @@ -1097,48 +1071,6 @@
  10.272  	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
  10.273  }
  10.274  
  10.275 -static int
  10.276 -download_packages(struct razor_set *system, struct razor_set *next)
  10.277 -{
  10.278 -	struct razor_install_iterator *ii;
  10.279 -	struct razor_package *package;
  10.280 -	enum razor_install_action action;
  10.281 -	const char *name, *version, *arch;
  10.282 -	char *file, *url, *s;
  10.283 -	int errors = 0, count;
  10.284 -
  10.285 -	ii = razor_set_create_install_iterator(system, next);
  10.286 -	while (razor_install_iterator_next(ii, &package, &action, &count)) {
  10.287 -		if (action != RAZOR_INSTALL_ACTION_ADD)
  10.288 -			continue;
  10.289 -
  10.290 -		razor_package_get_details(next, package,
  10.291 -					  RAZOR_DETAIL_NAME, &name,
  10.292 -					  RAZOR_DETAIL_VERSION, &version,
  10.293 -					  RAZOR_DETAIL_ARCH, &arch,
  10.294 -					  RAZOR_DETAIL_LAST);
  10.295 -		
  10.296 -		s = rpm_filename(name, version, arch);
  10.297 -		file = razor_concat("Packages/", s, NULL);
  10.298 -		url = razor_path_relative_to_uri(yum_url, file, NULL);
  10.299 -		free(file);
  10.300 -		file = razor_concat("rpms/", s, NULL);
  10.301 -		free(s);
  10.302 -		if (download_if_missing(url, file) < 0)
  10.303 -			errors++;
  10.304 -		free(file);
  10.305 -		free(url);
  10.306 -	}
  10.307 -	razor_install_iterator_destroy(ii);
  10.308 -
  10.309 -	if (errors > 0) {
  10.310 -		fprintf(stderr, "failed to download %d packages\n", errors);
  10.311 -                return -1;
  10.312 -        }
  10.313 -
  10.314 -	return 0;
  10.315 -}
  10.316 -
  10.317  static struct razor_set *
  10.318  relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
  10.319  		  struct razor_relocations *relocations)
  10.320 @@ -1179,12 +1111,7 @@
  10.321  		s = razor_concat("Packages/", filename, NULL);
  10.322  		uri = razor_path_relative_to_uri(yum_url, s, NULL);
  10.323  		free(s);
  10.324 -		file = razor_concat("rpms/", filename, NULL);
  10.325  		free(filename);
  10.326 -		download_if_missing(uri, file);
  10.327 -		free(uri);
  10.328 -		uri = razor_path_to_uri(file);
  10.329 -		free(file);
  10.330  		rpm = razor_rpm_open(uri, &error);
  10.331  		free(uri);
  10.332  		if (rpm == NULL) {
  10.333 @@ -1255,14 +1182,15 @@
  10.334  				  RAZOR_DETAIL_ARCH, &arch,
  10.335  				  RAZOR_DETAIL_LAST);
  10.336  
  10.337 +	s = rpm_filename(name, version, arch);
  10.338 +	file = razor_concat("Packages/", s, NULL);
  10.339 +	free(s);
  10.340 +	uri = razor_path_relative_to_uri(yum_url, file, NULL);
  10.341 +	free(file);
  10.342 +
  10.343  	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  10.344 -		printf("install %s-%s\n", name, version);
  10.345 +		printf("install %s\n", uri);
  10.346  
  10.347 -	s = rpm_filename(name, version, arch);
  10.348 -	file = razor_concat("rpms/", s, NULL);
  10.349 -	free(s);
  10.350 -	uri = razor_path_to_uri(file);
  10.351 -	free(file);
  10.352  	rpm = razor_rpm_open(uri, &error);
  10.353  	free(uri);
  10.354  	if (rpm == NULL) {
  10.355 @@ -1510,33 +1438,10 @@
  10.356  		}
  10.357  	}
  10.358  
  10.359 -	if (razor_atomic_create_dir(atomic, "file:rpms",
  10.360 -				    S_IRWXU | S_IRWXG | S_IRWXO) ||
  10.361 -	    razor_atomic_commit(atomic)) {
  10.362 -		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  10.363 -		razor_transaction_destroy(trans);
  10.364 -		razor_set_unref(upstream);
  10.365 -		razor_root_close(root);
  10.366 -		razor_atomic_destroy(atomic);
  10.367 -		if (relocations)
  10.368 -			razor_relocations_destroy(relocations);
  10.369 -		return 1;
  10.370 -	}
  10.371 -
  10.372  	razor_atomic_destroy(atomic);
  10.373  
  10.374  	next = razor_transaction_commit(trans);
  10.375  
  10.376 -	if (download_packages(system, next) < 0) {
  10.377 -		razor_set_unref(next);
  10.378 -		razor_transaction_destroy(trans);
  10.379 -		razor_set_unref(upstream);
  10.380 -		razor_root_close(root);
  10.381 -		if (relocations)
  10.382 -			razor_relocations_destroy(relocations);
  10.383 -                return 1;
  10.384 -        }
  10.385 -
  10.386  	retval = update_system(root, relocations, trans, next,
  10.387  			       do_update ? "Update" : "Install");
  10.388  
  10.389 @@ -1975,6 +1880,8 @@
  10.390  		return 1;
  10.391  	}
  10.392  
  10.393 +	init_uri_handler();
  10.394 +
  10.395  	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  10.396  		if (strcmp(razor_commands[i].name, argv[main_optind]) == 0)
  10.397  			return razor_commands[i].func(argc - main_optind,
    11.1 --- a/test/Makefile.am	Mon Jul 04 10:48:18 2016 +0100
    11.2 +++ b/test/Makefile.am	Mon Jul 04 13:04:19 2016 +0100
    11.3 @@ -4,38 +4,60 @@
    11.4  if HAVE_LUA
    11.5    check_SCRIPTS += lua mult-install
    11.6  endif
    11.7 +if HAVE_ZIP
    11.8 +  check_SCRIPTS += archive
    11.9 +endif
   11.10 +if HAVE_CURL
   11.11 +if !MSWIN_API
   11.12 +  check_SCRIPTS += curl
   11.13 +endif
   11.14 +endif
   11.15  check_SCRIPTS += order non-ascii relative-root
   11.16  
   11.17 -relocate:	relocate.sh primary.xml.gz
   11.18 +if !MSWIN_API
   11.19 +  check_PROGRAMS = tftpd
   11.20 +endif
   11.21 +
   11.22 +if INSTALL_TEST_PROGRAMS
   11.23 +  bin_PROGRAMS = $(check_PROGRAMS)
   11.24 +endif
   11.25 +
   11.26 +relocate:	relocate.sh base/repodata/primary.xml.gz
   11.27  	cp $(srcdir)/relocate.sh relocate
   11.28  
   11.29 -named-root:	named-root.sh primary.xml.gz
   11.30 +named-root:	named-root.sh base/repodata/primary.xml.gz
   11.31  	cp $(srcdir)/named-root.sh named-root
   11.32  
   11.33 -remove:	remove.sh primary.xml.gz
   11.34 +remove:	remove.sh base/repodata/primary.xml.gz
   11.35  	cp $(srcdir)/remove.sh remove
   11.36  
   11.37  update:	update.sh base/repodata/primary.xml.gz updates/repodata/primary.xml.gz
   11.38  	cp $(srcdir)/update.sh update
   11.39  
   11.40 -details:	details.sh primary.xml.gz
   11.41 +details:	details.sh base/repodata/primary.xml.gz
   11.42  	cp $(srcdir)/details.sh details
   11.43  
   11.44 -order:	order.sh primary.xml.gz
   11.45 +order:	order.sh base/repodata/primary.xml.gz
   11.46  	cp $(srcdir)/order.sh order
   11.47  
   11.48 -non-ascii:	non-ascii.sh primary.xml.gz
   11.49 +non-ascii:	non-ascii.sh base/repodata/primary.xml.gz
   11.50  	cp $(srcdir)/non-ascii.sh non-ascii
   11.51  
   11.52 -relative-root:	relative-root.sh primary.xml.gz
   11.53 +relative-root:	relative-root.sh base/repodata/primary.xml.gz
   11.54  	cp $(srcdir)/relative-root.sh relative-root
   11.55  
   11.56 -lua:	lua.sh primary.xml.gz
   11.57 +lua:	lua.sh base/repodata/primary.xml.gz
   11.58  	cp $(srcdir)/lua.sh lua
   11.59  
   11.60 -mult-install:	mult-install.sh primary.xml.gz
   11.61 +mult-install:	mult-install.sh base/repodata/primary.xml.gz
   11.62  	cp $(srcdir)/mult-install.sh mult-install
   11.63  
   11.64 +archive:	archive.sh base.zip
   11.65 +	cp $(srcdir)/archive.sh archive
   11.66 +
   11.67 +curl:	curl.sh tftpd base/repodata/primary.xml.gz
   11.68 +	cp $(srcdir)/curl.sh curl
   11.69 +
   11.70  base/repodata/primary.xml.gz:	zsh.spec zsh2.spec zip.spec zap.spec \
   11.71  		filesystem.spec Makefile
   11.72  	rm -rf rpmbuild base
   11.73 @@ -52,6 +74,9 @@
   11.74  	rm -rf rpmbuild
   11.75  	createrepo --simple-md-filenames base
   11.76  
   11.77 +base.zip:	base/repodata/primary.xml.gz
   11.78 +	(cd base && zip -r ../$@ *)
   11.79 +
   11.80  updates/repodata/primary.xml.gz:	zip.spec Makefile
   11.81  	rm -rf rpmbuild updates
   11.82  	mkdir -p rpmbuild/BUILD rpmbuild/RPMS
   11.83 @@ -62,11 +87,6 @@
   11.84  	rm -rf rpmbuild
   11.85  	createrepo --simple-md-filenames updates
   11.86  
   11.87 -primary.xml.gz:	base/repodata/primary.xml.gz
   11.88 -	cp base/repodata/primary.xml.gz base/repodata/filelists.xml.gz .
   11.89 -	rm -rf rpms
   11.90 -	ln -s base/Packages rpms
   11.91 -
   11.92  TESTS = $(check_SCRIPTS)
   11.93  
   11.94  EXTRA_DIST = 			\
   11.95 @@ -79,6 +99,8 @@
   11.96  	order.sh		\
   11.97  	non-ascii.sh		\
   11.98  	relative-root.sh	\
   11.99 +	archive.sh		\
  11.100 +	curl.sh			\
  11.101  	mult-install.sh		\
  11.102  	lua.sh			\
  11.103  	remove.sh		\
  11.104 @@ -89,6 +111,7 @@
  11.105  	relocate.sh
  11.106  
  11.107  MOSTLYCLEANFILES =		\
  11.108 +	base.zip		\
  11.109  	primary.xml.gz		\
  11.110  	filelists.xml.gz	\
  11.111  	$(check_SCRIPTS)	\
  11.112 @@ -97,4 +120,4 @@
  11.113  
  11.114  clean-local :
  11.115  	rm -f *~
  11.116 -	rm -rf repodata rpms base updates
  11.117 +	rm -rf base updates
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/archive.sh	Mon Jul 04 13:04:19 2016 +0100
    12.3 @@ -0,0 +1,29 @@
    12.4 +#!/bin/sh
    12.5 +if [ $# -gt 0 ]; then
    12.6 +    razor="$1"
    12.7 +else
    12.8 +    razor=`pwd`/../src/razor
    12.9 +fi
   12.10 +check_file()
   12.11 +{
   12.12 +    (cd $scratchdir; $razor list-files) | grep -F -x "$1" > /dev/null
   12.13 +    if [ $? -ne 0 ]; then
   12.14 +	echo $1: Not in database >&2
   12.15 +	(cd $scratchdir; $razor list-files) >&2
   12.16 +	exit 1
   12.17 +    fi
   12.18 +    if [ ! -e "$tmproot$1" ]; then 
   12.19 +	echo $1: Not in filesystem >&2
   12.20 +	ls -R "$tmproot" >&2
   12.21 +	exit 1
   12.22 +    fi
   12.23 +}
   12.24 +tmproot=`mktemp -dt` || exit 1
   12.25 +export RAZOR_ROOT="file:$tmproot"
   12.26 +scratchdir=`mktemp -dt` || exit 1
   12.27 +(cd $scratchdir; $razor init) || exit 1
   12.28 +export YUM_URL="file:`pwd`/base.zip"
   12.29 +(cd $scratchdir; $razor import-yum) || exit 1
   12.30 +(cd $scratchdir; $razor install zap) || exit 1
   12.31 +check_file /usr/bin/zap
   12.32 +rm -rf "$scratchdir" "$tmproot"
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/test/curl.sh	Mon Jul 04 13:04:19 2016 +0100
    13.3 @@ -0,0 +1,50 @@
    13.4 +#!/bin/bash
    13.5 +if [ $# -gt 0 ]; then
    13.6 +    razor="$1"
    13.7 +else
    13.8 +    razor=`pwd`/../src/razor
    13.9 +fi
   13.10 +check_file()
   13.11 +{
   13.12 +    $razor list-files | grep -F -x "$1" > /dev/null
   13.13 +    if [ $? -ne 0 ]; then
   13.14 +	echo $1: Not in database >&2
   13.15 +	$razor list-files >&2
   13.16 +	exit 1
   13.17 +    fi
   13.18 +    if [ ! -e "$tmproot$1" ]; then 
   13.19 +	echo $1: Not in filesystem >&2
   13.20 +	ls -R "$tmproot" >&2
   13.21 +	exit 1
   13.22 +    fi
   13.23 +}
   13.24 +tmproot=`mktemp -dt` || exit 1
   13.25 +export RAZOR_ROOT="file:$tmproot"
   13.26 +scratchdir=`mktemp -dt` || exit 1
   13.27 +(cd base && ../tftpd $scratchdir/tftpd.pid $scratchdir/tftpd.port) || exit 1
   13.28 +cd $scratchdir
   13.29 +port=`cat tftpd.port`
   13.30 +pid=`cat tftpd.pid`
   13.31 +export YUM_URL="tftp://localhost:$port/"
   13.32 +if $razor init; then
   13.33 +    :
   13.34 +else
   13.35 +    kill $pid
   13.36 +    exit 1
   13.37 +fi
   13.38 +if $razor import-yum; then
   13.39 +    :
   13.40 +else
   13.41 +    kill $pid
   13.42 +    exit 1
   13.43 +fi
   13.44 +if $razor install zap; then
   13.45 +    :
   13.46 +else
   13.47 +    kill $pid
   13.48 +    exit 1
   13.49 +fi
   13.50 +check_file /usr/bin/zap
   13.51 +rm -rf "$scratchdir" "$tmproot"
   13.52 +kill $pid
   13.53 +exit 0
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/tftpd.c	Mon Jul 04 13:04:19 2016 +0100
    14.3 @@ -0,0 +1,231 @@
    14.4 +/*
    14.5 + * Copyright (C) 2016  J. Ali Harlow <ali@juiblex.co.uk>
    14.6 + *
    14.7 + * This program is free software; you can redistribute it and/or modify
    14.8 + * it under the terms of the GNU General Public License as published by
    14.9 + * the Free Software Foundation; either version 2 of the License, or
   14.10 + * (at your option) any later version.
   14.11 + *
   14.12 + * This program is distributed in the hope that it will be useful,
   14.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14.15 + * GNU General Public License for more details.
   14.16 + *
   14.17 + * You should have received a copy of the GNU General Public License along
   14.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
   14.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   14.20 + */
   14.21 +
   14.22 +#include "config.h"
   14.23 +
   14.24 +#include <stdlib.h>
   14.25 +#include <string.h>
   14.26 +#include <stdio.h>
   14.27 +#include <errno.h>
   14.28 +#include <unistd.h>
   14.29 +#include <sys/types.h>
   14.30 +#include <sys/socket.h>
   14.31 +#include <netinet/in.h>
   14.32 +#include <netinet/ip.h>
   14.33 +#include <arpa/tftp.h>
   14.34 +
   14.35 +/*
   14.36 + * A simple TFTP server suitable only for use on the loopback interface
   14.37 + * (it has no support for retransmitting lost packets).
   14.38 + */
   14.39 +
   14.40 +char inbuf[SEGSIZE+4];
   14.41 +char outbuf[SEGSIZE+4];
   14.42 +
   14.43 +int send_error(int s, const struct sockaddr *client, socklen_t client_addr_len,
   14.44 +	       unsigned short code,const char *message)
   14.45 +{
   14.46 +	int r;
   14.47 +	char *buf;
   14.48 +	size_t len;
   14.49 +
   14.50 +	len = 4 + strlen(message) + 1;
   14.51 +	buf = malloc(len);
   14.52 +	((unsigned short *)buf)[0] = htons(ERROR);
   14.53 +	((unsigned short *)buf)[1] = htons(code);
   14.54 +	strcpy(buf + 4, message);
   14.55 +	r = sendto(s, buf, len, 0, client, client_addr_len);
   14.56 +	free(buf);
   14.57 +
   14.58 +	return r;
   14.59 +}
   14.60 +
   14.61 +int send_file(int s, const struct sockaddr *client, socklen_t client_addr_len,
   14.62 +	       const char *path, const char *mode)
   14.63 +{
   14.64 +	const char *dotdot, *p;
   14.65 +	FILE *fp;
   14.66 +	size_t nb;
   14.67 +	int block = 0;
   14.68 +
   14.69 +	if (strcasecmp(mode, "octet")) {
   14.70 +		send_error(s, client, client_addr_len, EBADOP, "Bad mode");
   14.71 +		return -1;
   14.72 +	}
   14.73 +
   14.74 +	if (!*path || *path == '/') {
   14.75 +		send_error(s, client, client_addr_len, EACCESS,
   14.76 +			   "Access denied");
   14.77 +		return -1;
   14.78 +	}
   14.79 +
   14.80 +	for (p = path; *p;) {
   14.81 +		dotdot = strstr(p, "..");
   14.82 +		if (!dotdot)
   14.83 +			break;
   14.84 +		if ((dotdot == path || dotdot[-1] == '/') &&
   14.85 +		    (dotdot[2] == '/' || dotdot[2] == '\0')) {
   14.86 +			send_error(s, client, client_addr_len, EACCESS,
   14.87 +				   "Access denied");
   14.88 +			return -1;
   14.89 +		}
   14.90 +		p = dotdot + 2;
   14.91 +	}
   14.92 +
   14.93 +	fp = fopen(path, "rb");
   14.94 +
   14.95 +	if (!fp) {
   14.96 +		if (errno == ENOENT)
   14.97 +			send_error(s, client, client_addr_len, ENOTFOUND,
   14.98 +				   strerror(errno));
   14.99 +		else if (errno == EACCES)
  14.100 +			send_error(s, client, client_addr_len, EACCESS,
  14.101 +				   strerror(errno));
  14.102 +		else
  14.103 +			send_error(s, client, client_addr_len, EUNDEF,
  14.104 +				   strerror(errno));
  14.105 +		return -1;
  14.106 +	}
  14.107 +
  14.108 +	((unsigned short *)outbuf)[0] = htons(DATA);
  14.109 +
  14.110 +	while((nb = fread(outbuf + 4, 1, SEGSIZE, fp)) >= 0)
  14.111 +	{
  14.112 +		((unsigned short *)outbuf)[1] = htons(++block);
  14.113 +		if (sendto(s, outbuf, nb + 4, 0, client, client_addr_len) < 0) {
  14.114 +			perror("sendto");
  14.115 +			fclose(fp);
  14.116 +			return -1;
  14.117 +		}
  14.118 +
  14.119 +		/* Discard ACKs */
  14.120 +		(void)recvfrom(s, inbuf, sizeof(inbuf), 0, NULL, NULL);
  14.121 +		
  14.122 +		if (nb < SEGSIZE)
  14.123 +			break;
  14.124 +	}
  14.125 +
  14.126 +	fclose(fp);
  14.127 +
  14.128 +	return 0;
  14.129 +}
  14.130 +
  14.131 +void serve(int s)
  14.132 +{
  14.133 +	char *filename, *mode;
  14.134 +	struct sockaddr_storage client;
  14.135 +	socklen_t client_addr_len;
  14.136 +	ssize_t nb;
  14.137 +
  14.138 +	for(;;) {
  14.139 +		client_addr_len = sizeof(client);
  14.140 +		nb = recvfrom(s, inbuf, sizeof(inbuf), 0,
  14.141 +			      (struct sockaddr *)&client, &client_addr_len);
  14.142 +
  14.143 +		if (nb < 0) {
  14.144 +			perror("recvfrom");
  14.145 +			exit(1);
  14.146 +		}
  14.147 +
  14.148 +		if (nb >= 2) {
  14.149 +			switch (ntohs(*(unsigned short *)inbuf)) {
  14.150 +			case RRQ:
  14.151 +				filename = inbuf + 2;
  14.152 +				mode = memchr(filename, '\0', nb - 2);
  14.153 +				if (!mode) {
  14.154 +					send_error(s,
  14.155 +						   (struct sockaddr *)&client,
  14.156 +						   client_addr_len, EBADOP,
  14.157 +						   "Bad request");
  14.158 +					break;
  14.159 +				}
  14.160 +				mode++;
  14.161 +				if (!memchr(mode, '\0', nb - (mode - inbuf))) {
  14.162 +					send_error(s,
  14.163 +						   (struct sockaddr *)&client,
  14.164 +						   client_addr_len, EBADOP,
  14.165 +						   "Bad request");
  14.166 +					break;
  14.167 +				}
  14.168 +				send_file(s, (struct sockaddr *)&client,
  14.169 +					  client_addr_len, filename, mode);
  14.170 +				break;
  14.171 +			case WRQ:
  14.172 +				send_error(s, (struct sockaddr *)&client,
  14.173 +					   client_addr_len, EACCESS,
  14.174 +					   "Access denied");
  14.175 +				break;
  14.176 +			case DATA:
  14.177 +			case ACK:
  14.178 +			case ERROR:
  14.179 +				break;
  14.180 +			}
  14.181 +		}
  14.182 +	}
  14.183 +}
  14.184 +
  14.185 +main(int argc, char **argv)
  14.186 +{
  14.187 +	int s;
  14.188 +	pid_t pid;
  14.189 +	FILE *fp;
  14.190 +	in_port_t port;
  14.191 +	struct sockaddr_in sin = {0,};
  14.192 +
  14.193 +	s = socket(AF_INET, SOCK_DGRAM, 0);
  14.194 +	if (s < 0) {
  14.195 +		perror("socket");
  14.196 +		exit(1);
  14.197 +	}
  14.198 +
  14.199 +	sin.sin_family = AF_INET;
  14.200 +	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  14.201 +
  14.202 +	for (port = 0;; port++) {
  14.203 +		sin.sin_port = htons(IPPORT_USERRESERVED + port);
  14.204 +		if (!bind(s, (struct sockaddr *)&sin, sizeof(sin)))
  14.205 +			break;
  14.206 +		if (errno != EADDRINUSE || port >= 1023) {
  14.207 +			perror("bind");
  14.208 +			exit(1);
  14.209 +		}
  14.210 +	}
  14.211 +
  14.212 +	if (argc > 2) {
  14.213 +		fp = fopen(argv[2], "w");
  14.214 +		if (fp) {
  14.215 +			fprintf(fp, "%ld\n", (long)ntohs(sin.sin_port));
  14.216 +			fclose(fp);
  14.217 +		}
  14.218 +
  14.219 +		pid = fork();
  14.220 +		if (pid) {
  14.221 +			fp = fopen(argv[1], "w");
  14.222 +			if (fp) {
  14.223 +				fprintf(fp, "%ld\n", (long)pid);
  14.224 +				fclose(fp);
  14.225 +			}
  14.226 +			exit(0);
  14.227 +		}
  14.228 +	} else
  14.229 +		printf("%d\n", ntohs(sin.sin_port));
  14.230 +
  14.231 +	serve(s);
  14.232 +
  14.233 +	exit(0);
  14.234 +}