Switch to a URI-based API
authorJ. Ali Harlow <ali@juiblex.co.uk>
Mon Jul 04 10:48:18 2016 +0100 (2016-07-04)
changeset 475008c75a5e08d
parent 474 7442b30ecaae
child 476 48e45439fd9a
Switch to a URI-based API
librazor/Makefile.am
librazor/atomic-actions.c
librazor/atomic-emulate.c
librazor/atomic-ktm.c
librazor/atomic-none.c
librazor/atomic.c
librazor/dump.c
librazor/path.c
librazor/razor-internal.h
librazor/razor.c
librazor/razor.h.in
librazor/root.c
librazor/rpm.c
librazor/test-lua.c
librazor/test-pfu.c
librazor/test-uri.c
librazor/transaction.c
librazor/types/array.c
librazor/types/types.h
librazor/uri-io.c
librazor/uri.c
librazor/uri.h
librazor/util.c
src/import-rpmdb.c
src/main.c
test/Makefile.am
test/aljip.spec
test/details.sh
test/lua.sh
test/mult-install.sh
test/named-root.sh
test/non-ascii.sh
test/order.sh
test/relative-root.sh
test/relocate.sh
test/remove.sh
test/update.sh
     1.1 --- a/librazor/Makefile.am	Sat Jun 11 17:56:48 2016 +0100
     1.2 +++ b/librazor/Makefile.am	Mon Jul 04 10:48:18 2016 +0100
     1.3 @@ -14,7 +14,7 @@
     1.4  	-DPACKAGE_LIB_DIR=\""$(libdir)"\"
     1.5  
     1.6  lib_LTLIBRARIES = librazor.la
     1.7 -check_PROGRAMS = test-pfu
     1.8 +check_PROGRAMS = test-pfu test-uri
     1.9  if HAVE_LUA
    1.10    check_PROGRAMS += test-lua
    1.11  endif
    1.12 @@ -30,11 +30,14 @@
    1.13  
    1.14  librazor_la_SOURCES =                                	\
    1.15  	razor-internal.h				\
    1.16 +	uri.h						\
    1.17  	razor.h						\
    1.18  	razor.c						\
    1.19  	root.c						\
    1.20  	dump.c						\
    1.21  	util.c						\
    1.22 +	uri-io.c					\
    1.23 +	uri.c						\
    1.24  	path.c						\
    1.25  	rpm.c						\
    1.26  	iterator.c					\
    1.27 @@ -58,15 +61,22 @@
    1.28  	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
    1.29  
    1.30  test_pfu_SOURCES = test-pfu.c
    1.31 -test_pfu_LDADD = path.lo util.lo error.lo types/libtypes.la \
    1.32 +test_pfu_LDADD = path.lo uri.lo util.lo error.lo types/libtypes.la \
    1.33  	../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
    1.34  
    1.35  TESTS = test-pfu
    1.36  
    1.37 +test_uri_SOURCES = test-uri.c
    1.38 +test_uri_CFLAGS = $(AM_CFLAGS)
    1.39 +test_uri_LDADD = uri.lo util.lo path.lo error.lo types/libtypes.la \
    1.40 +	$(LUA_LIBS) ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
    1.41 +
    1.42 +TESTS += test-uri
    1.43 +
    1.44  if HAVE_LUA
    1.45    test_lua_SOURCES = test-lua.c
    1.46 -  test_lua_LDADD = lua.lo util.lo error.lo types/libtypes.la $(LUA_LIBS) \
    1.47 -	../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
    1.48 +  test_lua_LDADD = lua.lo uri.lo uri-io.lo util.lo path.lo error.lo \
    1.49 +  	types/libtypes.la $(LUA_LIBS) ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS)
    1.50  
    1.51    TESTS += test-lua
    1.52  endif
     2.1 --- a/librazor/atomic-actions.c	Sat Jun 11 17:56:48 2016 +0100
     2.2 +++ b/librazor/atomic-actions.c	Mon Jul 04 10:48:18 2016 +0100
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (C) 2012  J. Ali Harlow <ali@juiblex.co.uk>
     2.6 + * Copyright (C) 2012, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     2.7   *
     2.8   * This program is free software; you can redistribute it and/or modify
     2.9   * it under the terms of the GNU General Public License as published by
    2.10 @@ -25,9 +25,6 @@
    2.11  #include <string.h>
    2.12  #include <limits.h>
    2.13  #include <errno.h>
    2.14 -#include <sys/stat.h>
    2.15 -#include <sys/types.h>
    2.16 -#include <dirent.h>
    2.17  #include <assert.h>
    2.18  #include "razor-internal.h"
    2.19  
    2.20 @@ -87,7 +84,7 @@
    2.21  	while(action) {
    2.22  		a = atomic_action_list_pop_head(&action);
    2.23  
    2.24 -		free(a->args.path);
    2.25 +		free(a->args.uri);
    2.26  
    2.27  		switch(a->type) {
    2.28  		case ACTION_MAKE_DIRS:
    2.29 @@ -166,13 +163,11 @@
    2.30  
    2.31  	strcpy(buffer, action->args.u.make_dirs.root);
    2.32  	p = buffer + strlen(buffer);
    2.33 -	slash = action->args.path;
    2.34 +	slash = action->args.uri;
    2.35 +	if (p > buffer && p[-1] != ':' && p[-1] != '/' && *slash != '/')
    2.36 +		*p++ = '/';
    2.37  	for (; *slash != '\0'; slash = next) {
    2.38 -#ifdef MSWIN_API
    2.39 -		next = strpbrk(slash + 1, "/\\");
    2.40 -#else
    2.41  		next = strchr(slash + 1, '/');
    2.42 -#endif
    2.43  		if (next == NULL)
    2.44  			break;
    2.45  
    2.46 @@ -184,7 +179,7 @@
    2.47  			continue;
    2.48  
    2.49  		prim = atomic_action_new(ACTION_CREATE_DIR);
    2.50 -		prim->args.path = strdup(buffer);
    2.51 +		prim->args.uri = strdup(buffer);
    2.52  		prim->args.u.create_dir.mode = S_IRWXU | S_IRWXG | S_IRWXO;
    2.53  		primitives = atomic_action_list_prepend(primitives, prim);
    2.54  	}
    2.55 @@ -198,12 +193,8 @@
    2.56  static struct atomic_action *
    2.57  atomic_action_remove(struct razor_atomic *atomic, struct atomic_action *action)
    2.58  {
    2.59 -#ifdef MSWIN_API
    2.60 -	wchar_t *path;
    2.61 -	_WDIR *dir;
    2.62 -#else
    2.63 -	DIR *dir;
    2.64 -#endif
    2.65 +	void *dir;
    2.66 +	char *name;
    2.67  	struct atomic_action *prim;
    2.68  
    2.69  	if (razor_atomic_in_error_state(atomic)) {
    2.70 @@ -214,27 +205,20 @@
    2.71  	/*
    2.72  	 * Non-empty directories should NOT be removed
    2.73  	 */
    2.74 -#ifdef MSWIN_API
    2.75 -	path = razor_utf8_to_utf16(action->args.path, -1);
    2.76 -
    2.77 -	dir = _wopendir(path);
    2.78 -	if (dir && _wreaddir(dir)) {
    2.79 -		atomic_action_free(action);
    2.80 -		action = NULL;
    2.81 +	dir = razor_uri_opendir(action->args.uri, NULL);
    2.82 +	if (dir) {
    2.83 +		name = razor_uri_readdir(dir, NULL);
    2.84 +		razor_uri_closedir(dir, NULL);
    2.85 +		if (name) {
    2.86 +			free(name);
    2.87 +			atomic_action_free(action);
    2.88 +			action = NULL;
    2.89 +		}
    2.90  	}
    2.91 -	_wclosedir(dir);
    2.92 -#else
    2.93 -	dir = opendir(action->args.path);
    2.94 -	if (dir && readdir(dir)) {
    2.95 -		atomic_action_free(action);
    2.96 -		action = NULL;
    2.97 -	}
    2.98 -	closedir(dir);
    2.99 -#endif
   2.100  
   2.101  	if (action) {
   2.102  		prim = atomic_action_new(ACTION_MOVE);
   2.103 -		prim->args.path = strdup(action->args.path);
   2.104 +		prim->args.uri = strdup(action->args.uri);
   2.105  		prim->args.u.move.dest = atomic_action_attic_tmpnam(atomic);
   2.106  
   2.107  		atomic_action_free(action);
   2.108 @@ -249,7 +233,7 @@
   2.109  			 struct atomic_action *action)
   2.110  {
   2.111  	mode_t mode;
   2.112 -	struct stat buf;
   2.113 +	struct razor_error **error;
   2.114  
   2.115  	if (razor_atomic_in_error_state(atomic)) {
   2.116  		atomic_action_free(action);
   2.117 @@ -258,21 +242,14 @@
   2.118  
   2.119  	mode = action->args.u.create_dir.mode & (S_IRWXU | S_IRWXG | S_IRWXO);
   2.120  
   2.121 -	if (!mkdir(action->args.path, mode))
   2.122 +	if (atomic->error)
   2.123 +		error = NULL;
   2.124 +	else
   2.125 +		error = &atomic->error;
   2.126 +
   2.127 +	if (!razor_uri_mkdir(action->args.uri, mode, error))
   2.128  		return action;
   2.129  
   2.130 -	if (errno != EEXIST || stat(action->args.path, &buf)) {
   2.131 -		if (!atomic->error)
   2.132 -			atomic->error = razor_error_new_posix(action->args.path);
   2.133 -		atomic_action_free(action);
   2.134 -		return NULL;
   2.135 -	}
   2.136 -
   2.137 -	if (!S_ISDIR(buf.st_mode) && !atomic->error)
   2.138 -		atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST,
   2.139 -						    action->args.path,
   2.140 -						    "Not a directory");
   2.141 -
   2.142  	atomic_action_free(action);
   2.143  	return NULL;
   2.144  }
   2.145 @@ -285,9 +262,9 @@
   2.146  		return NULL;
   2.147  	}
   2.148  
   2.149 -	if (rmdir(action->args.path) < 0) {
   2.150 +	if (rmdir(action->args.uri) < 0) {
   2.151  		if (!atomic->error)
   2.152 -			atomic->error = razor_error_new_posix(action->args.path);
   2.153 +			atomic->error = razor_error_new_posix(action->args.uri);
   2.154  		atomic_action_free(action);
   2.155  		return NULL;
   2.156  	} else
   2.157 @@ -306,10 +283,10 @@
   2.158  		return NULL;
   2.159  	}
   2.160  
   2.161 -	r = symlink(action->args.u.create_symlink.target, action->args.path);
   2.162 +	r = symlink(action->args.u.create_symlink.target, action->args.uri);
   2.163  	if (r < 0) {
   2.164  		if (!atomic->error)
   2.165 -			atomic->error = razor_error_new_posix(action->args.path);
   2.166 +			atomic->error = razor_error_new_posix(action->args.uri);
   2.167  		atomic_action_free(action);
   2.168  		return NULL;
   2.169  	}
   2.170 @@ -321,14 +298,19 @@
   2.171  atomic_action_remove_symlink(struct razor_atomic *atomic,
   2.172  			     struct atomic_action *action)
   2.173  {
   2.174 +	struct razor_error **error;
   2.175 +
   2.176  	if (razor_atomic_in_error_state(atomic)) {
   2.177  		atomic_action_free(action);
   2.178  		return NULL;
   2.179  	}
   2.180  
   2.181 -	if (unlink(action->args.path) < 0) {
   2.182 -		if (!atomic->error)
   2.183 -			atomic->error = razor_error_new_posix(action->args.path);
   2.184 +	if (atomic->error)
   2.185 +		error = NULL;
   2.186 +	else
   2.187 +		error = &atomic->error;
   2.188 +
   2.189 +	if (razor_uri_unlink(action->args.uri, error)) {
   2.190  		atomic_action_free(action);
   2.191  		return NULL;
   2.192  	}
   2.193 @@ -338,52 +320,16 @@
   2.194  #endif
   2.195  
   2.196  static int
   2.197 -move_file(struct razor_atomic *atomic, const char *path, const char *dest)
   2.198 +move_file(struct razor_atomic *atomic, const char *uri, const char *dest)
   2.199  {
   2.200 -#ifdef MSWIN_API
   2.201 -	wchar_t *oldbuf, *newbuf;
   2.202 -	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   2.203 +	struct razor_error **error;
   2.204  
   2.205 -	newbuf = razor_utf8_to_utf16(dest, -1);
   2.206 -	oldbuf = razor_utf8_to_utf16(path, -1);
   2.207 +	if (atomic->error)
   2.208 +		error = NULL;
   2.209 +	else
   2.210 +		error = &atomic->error;
   2.211  
   2.212 -	/*
   2.213 -	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
   2.214 -	 * cover every case we care about _except_ replacing an empty
   2.215 -	 * directory with a file. Calling RemoveDirectory() will deal
   2.216 -	 * with this case while having no effect in all other cases.
   2.217 -	 */
   2.218 -	(void)RemoveDirectoryW(newbuf);
   2.219 -
   2.220 -	if (!MoveFileExW(oldbuf, newbuf, flags)) {
   2.221 -		if (!atomic->error)
   2.222 -			atomic->error = razor_error_new_mswin(newbuf,
   2.223 -							      GetLastError());
   2.224 -		return -1;
   2.225 -	}
   2.226 -
   2.227 -	free(newbuf);
   2.228 -	free(oldbuf);
   2.229 -#else
   2.230 -	int code;
   2.231 -	const char *object;
   2.232 -
   2.233 -	if (rename(path, dest)) {
   2.234 -		if (!atomic->error) {
   2.235 -			code = errno;
   2.236 -			if (access(path, F_OK) < 0)
   2.237 -				object = path;
   2.238 -			else
   2.239 -				object = dest;
   2.240 -			atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR,
   2.241 -							    code, object,
   2.242 -							    strerror(code));
   2.243 -		}
   2.244 -		return -1;
   2.245 -	}
   2.246 -#endif
   2.247 -
   2.248 -	return 0;
   2.249 +	return razor_uri_move(uri, dest, error);
   2.250  }
   2.251  
   2.252  static struct atomic_action *
   2.253 @@ -394,7 +340,7 @@
   2.254  		return NULL;
   2.255  	}
   2.256  
   2.257 -	if (move_file(atomic, action->args.path, action->args.u.move.dest)) {
   2.258 +	if (move_file(atomic, action->args.uri, action->args.u.move.dest)) {
   2.259  		atomic_action_free(action);
   2.260  		return NULL;
   2.261  	}
   2.262 @@ -410,7 +356,7 @@
   2.263  		return NULL;
   2.264  	}
   2.265  
   2.266 -	if (move_file(atomic, action->args.u.move.dest, action->args.path)) {
   2.267 +	if (move_file(atomic, action->args.u.move.dest, action->args.uri)) {
   2.268  		atomic_action_free(action);
   2.269  		return NULL;
   2.270  	}
     3.1 --- a/librazor/atomic-emulate.c	Sat Jun 11 17:56:48 2016 +0100
     3.2 +++ b/librazor/atomic-emulate.c	Mon Jul 04 10:48:18 2016 +0100
     3.3 @@ -1,5 +1,5 @@
     3.4  /*
     3.5 - * Copyright (C) 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
     3.6 + * Copyright (C) 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     3.7   *
     3.8   * This program is free software; you can redistribute it and/or modify
     3.9   * it under the terms of the GNU General Public License as published by
    3.10 @@ -24,12 +24,7 @@
    3.11  #include <stdio.h>
    3.12  #include <string.h>
    3.13  #include <unistd.h>
    3.14 -#include <sys/types.h>
    3.15 -#include <sys/stat.h>
    3.16  #include <fcntl.h>
    3.17 -#include <dirent.h>
    3.18 -#include <errno.h>
    3.19 -#include <unistd.h>
    3.20  #include "razor-internal.h"
    3.21  
    3.22  /*
    3.23 @@ -53,24 +48,23 @@
    3.24  
    3.25  static void recursive_remove(const char *directory)
    3.26  {
    3.27 -	DIR *dp;
    3.28 -	struct dirent *dirp;
    3.29 -	char *buf;
    3.30 +	void *dp;
    3.31 +	char *name, *buf;
    3.32  
    3.33 -	dp = opendir(directory);
    3.34 -	while((dirp = readdir(dp))) {
    3.35 -		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
    3.36 -			buf = malloc(strlen(directory) + strlen(dirp->d_name)
    3.37 -				     + 2);
    3.38 -			sprintf(buf, "%s/%s", directory, dirp->d_name);
    3.39 -			if (remove(buf) < 0)
    3.40 +	dp = razor_uri_opendir(directory, NULL);
    3.41 +
    3.42 +	if (dp) {
    3.43 +		while((name = razor_uri_readdir(dp, NULL))) {
    3.44 +			buf = razor_concat(directory, "/", name, NULL);
    3.45 +			free(name);
    3.46 +			if (razor_uri_unlink(buf, NULL) < 0)
    3.47  				recursive_remove(buf);
    3.48  			free(buf);
    3.49  		}
    3.50 +
    3.51 +		razor_uri_closedir(dp, NULL);
    3.52  	}
    3.53  
    3.54 -	closedir(dp);
    3.55 -
    3.56  	rmdir(directory);
    3.57  }
    3.58  
    3.59 @@ -129,53 +123,6 @@
    3.60  	free(atomic);
    3.61  }
    3.62  
    3.63 -#ifndef MSWIN_API
    3.64 -static char *absolute_path(const char *path)
    3.65 -{
    3.66 -	int len;
    3.67 -	char *result, *subpath, *p, *s, *t;
    3.68 -
    3.69 -	result = realpath(path, NULL);
    3.70 -
    3.71 -	if (!result && errno == ENOENT) {
    3.72 -		p = strdup(path);
    3.73 -		s = strrchr(p, '/');
    3.74 -
    3.75 -		while (s) {
    3.76 -			if (s == p) {
    3.77 -				result = strdup("/");
    3.78 -				break;
    3.79 -			}
    3.80 -
    3.81 -			*s = '\0';
    3.82 -			subpath = realpath(p, NULL);
    3.83 -
    3.84 -			if (subpath) {
    3.85 -				*s = '/';
    3.86 -				len = strlen(subpath);
    3.87 -				result = malloc(len + strlen(s) + 1);
    3.88 -				memcpy(result, subpath, len);
    3.89 -				strcpy(result + len, s);
    3.90 -				free(subpath);
    3.91 -				break;
    3.92 -			} else if (errno != ENOENT)
    3.93 -				break;
    3.94 -
    3.95 -			t = strrchr(p, '/');
    3.96 -			*s = '/';
    3.97 -			s = t;
    3.98 -		}
    3.99 -
   3.100 -		if (!s)
   3.101 -			result = realpath(".", NULL);
   3.102 -
   3.103 -		free(p);
   3.104 -	}
   3.105 -
   3.106 -	return result;
   3.107 -}
   3.108 -#endif
   3.109 -
   3.110  /*
   3.111   * We need a toplevel directory in which to hold temporary files
   3.112   * before they are committed. Since we can generally assume that
   3.113 @@ -186,14 +133,9 @@
   3.114   */
   3.115  
   3.116  static int
   3.117 -razor_atomic_set_toplevel_from_path(struct razor_atomic *atomic,
   3.118 -				    const char *path)
   3.119 +razor_atomic_set_toplevel_from_uri(struct razor_atomic *atomic,
   3.120 +				   const char *uri)
   3.121  {
   3.122 -#ifndef MSWIN_API
   3.123 -	dev_t filesystem;
   3.124 -	struct stat buf;
   3.125 -#endif
   3.126 -
   3.127  	if (razor_atomic_in_error_state(atomic))
   3.128  		return -1;
   3.129  
   3.130 @@ -201,231 +143,113 @@
   3.131  		return 0;
   3.132  
   3.133  #ifdef MSWIN_API
   3.134 -	if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\'
   3.135 -	    && strchr(path+3,'\\')) {
   3.136 -		/* We have a UNC path: \\servername\sharename... */
   3.137 -		const char *sharename, *root;
   3.138 -		int disklen;
   3.139 -
   3.140 -		sharename = strchr(path+3,'\\')+1;
   3.141 -		root = strchr(sharename,'\\');
   3.142 -		if (root)
   3.143 -		    disklen = root - path;
   3.144 -		else
   3.145 -		    disklen = strlen(path);
   3.146 -
   3.147 -		atomic->toplevel =
   3.148 -		  malloc(disklen + strlen("\\atomic-XXXXXX") + 1);
   3.149 -		memcpy(atomic->toplevel, path, disklen);
   3.150 -		strcpy(atomic->toplevel + disklen, "\\atomic-XXXXXX");
   3.151 -	} else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') &&
   3.152 -		    path[1]==':') {
   3.153 -		atomic->toplevel = strdup("X:\\atomic-XXXXXX");
   3.154 -		*atomic->toplevel = *path;
   3.155 -	} else {
   3.156 -		DWORD n;
   3.157 -		wchar_t *buf;
   3.158 -		char *dir;
   3.159 -
   3.160 -		n = GetCurrentDirectoryW(0, NULL);
   3.161 -		buf = malloc(n * sizeof(wchar_t));
   3.162 -
   3.163 -		if (GetCurrentDirectoryW(n, buf)) {
   3.164 -			dir = razor_utf16_to_utf8(buf, n - 1);
   3.165 -			razor_atomic_set_toplevel_from_path(atomic, dir);
   3.166 -
   3.167 -			free(dir);
   3.168 -			free(buf);
   3.169 -			return;
   3.170 -		} else
   3.171 -			atomic->toplevel = strdup("C:\\atomic-XXXXXX");
   3.172 -
   3.173 -		free(buf);
   3.174 -	}
   3.175 +	atomic->toplevel = razor_uri_mkdtemp_near(uri, "atomic-XXXXXX",
   3.176 +						   &atomic->error);
   3.177  #else
   3.178 -	{
   3.179 -		/*
   3.180 -		 * Find the mount point (assuming we can write to the
   3.181 -		 * whole filesystem). Otherwise stop at the first
   3.182 -		 * unwritable directory and take one step back.
   3.183 -		 */
   3.184 -		char *s, *abspath, saved;
   3.185 -		int len, can_step_back = 0;
   3.186 -
   3.187 -		abspath = absolute_path(path);
   3.188 -		if (!abspath) {
   3.189 -			atomic->error = razor_error_new_posix(path);
   3.190 -			return -1;
   3.191 -		}
   3.192 -
   3.193 -		if (stat(abspath, &buf) < 0) {
   3.194 -			if (errno == ENOENT)
   3.195 -				filesystem = 0;
   3.196 -			else {
   3.197 -				atomic->error = razor_error_new_posix(abspath);
   3.198 -				free(abspath);
   3.199 -				return -1;
   3.200 -			}
   3.201 -		} else
   3.202 -			filesystem = buf.st_dev;
   3.203 -
   3.204 -		len = strlen(abspath);
   3.205 -		while(len > 1 && (s = strrchr(abspath, '/'))) {
   3.206 -			if (s == abspath) {
   3.207 -				saved = s[1];
   3.208 -				s[1] = '\0';
   3.209 -				len = s + 1 - abspath;
   3.210 -			} else {
   3.211 -				s[0] = '\0';
   3.212 -				len = s - abspath;
   3.213 -			}
   3.214 -
   3.215 -			if (stat(abspath, &buf) < 0) {
   3.216 -				if (errno == ENOENT)
   3.217 -					continue;
   3.218 -				else {
   3.219 -				    atomic->error = razor_error_new_posix(abspath);
   3.220 -				    free(abspath);
   3.221 -				    return -1;
   3.222 -				}
   3.223 -			} else if (!filesystem)
   3.224 -				filesystem = buf.st_dev;
   3.225 -
   3.226 -			if (buf.st_dev != filesystem || access(abspath, W_OK)) {
   3.227 -				if (can_step_back) {
   3.228 -					if (s == abspath)
   3.229 -						s[1] = saved;
   3.230 -					else
   3.231 -						s[0] = '/';
   3.232 -				}
   3.233 -				len = strlen(abspath);
   3.234 -				break;
   3.235 -			} else
   3.236 -				can_step_back = 1;
   3.237 -		}
   3.238 -
   3.239 -		if (len == 1)
   3.240 -			len = 0;	/* Avoid an unslightly double slash. */
   3.241 -		atomic->toplevel = malloc(len + strlen("/.atomic-XXXXXX") + 1);
   3.242 -		memcpy(atomic->toplevel, abspath, len);
   3.243 -		strcpy(atomic->toplevel + len, "/.atomic-XXXXXX");
   3.244 -
   3.245 -		free(abspath);
   3.246 -	}
   3.247 +	atomic->toplevel = razor_uri_mkdtemp_near(uri, ".atomic-XXXXXX",
   3.248 +						   &atomic->error);
   3.249  #endif
   3.250  
   3.251 -	if (!mkdtemp(atomic->toplevel)) {
   3.252 -		int err = errno;
   3.253 -
   3.254 -#ifdef EACCES
   3.255 -		if (err == EACCES) {
   3.256 -			char *s = strdup("atomic-XXXXXX");
   3.257 -
   3.258 -#ifndef MSWIN_API
   3.259 -			if (stat(".", &buf) < 0) {
   3.260 -				atomic->error = razor_error_new_posix(".");
   3.261 -				free(s);
   3.262 -				free(atomic->toplevel);
   3.263 -				atomic->toplevel = NULL;
   3.264 -				return -1;
   3.265 -			}
   3.266 -			if (buf.st_dev != filesystem)
   3.267 -				/*
   3.268 -				 * Don't use a different filesystem. It will
   3.269 -				 * only fail later on (in rename) and cause
   3.270 -				 * an unhelpful error message (EXDEV).
   3.271 -				 */
   3.272 -				free(s);
   3.273 -			else
   3.274 -#endif
   3.275 -			if (mkdtemp(s)) {
   3.276 -				free(atomic->toplevel);
   3.277 -				atomic->toplevel = s;
   3.278 -				return 0;
   3.279 -			} else
   3.280 -				free(s);
   3.281 -		}
   3.282 -#endif
   3.283 -
   3.284 -		atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, err,
   3.285 -						    atomic->toplevel,
   3.286 -						    strerror(err));
   3.287 -
   3.288 -		free(atomic->toplevel);
   3.289 -		atomic->toplevel = NULL;
   3.290 -	}
   3.291 -
   3.292  	return !atomic->toplevel;
   3.293  }
   3.294  
   3.295 +/*
   3.296 + * If root_uri is empty, then uri can be a URI (but not a relative-ref; ie.,
   3.297 + * a scheme must be specified). If root_uri is non-empty, then it must be a
   3.298 + * URI (but not a relative-ref) and uri must be a non-empty path.
   3.299 + */
   3.300  RAZOR_EXPORT int
   3.301 -razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
   3.302 -		       const char *path)
   3.303 +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root_uri,
   3.304 +		       const char *uri)
   3.305  {
   3.306  	struct atomic_action *a;
   3.307 +	struct razor_uri ru;
   3.308 +	struct razor_error *tmp_error = NULL;
   3.309 +	char *fakeroot = NULL;
   3.310  
   3.311 -	razor_atomic_set_toplevel_from_path(atomic, *root ? root : path);
   3.312 +	razor_atomic_set_toplevel_from_uri(atomic, *root_uri ? root_uri : uri);
   3.313  
   3.314  	if (razor_atomic_in_error_state(atomic))
   3.315  		return -1;
   3.316  
   3.317 +	if (!*root_uri) {
   3.318 +		if (razor_uri_parse(&ru, uri, &tmp_error)) {
   3.319 +			razor_atomic_propagate_error(atomic, tmp_error, NULL);
   3.320 +			return -1;
   3.321 +		}
   3.322 +		if (*ru.path == '/') {
   3.323 +			free(ru.path);
   3.324 +			ru.path = strdup("/");
   3.325 +		} else {
   3.326 +			free(ru.path);
   3.327 +			ru.path = strdup("");
   3.328 +		}
   3.329 +		fakeroot = razor_uri_recompose(&ru);
   3.330 +		razor_uri_destroy(&ru);
   3.331 +		root_uri = fakeroot;
   3.332 +		uri += strlen(fakeroot);
   3.333 +	}
   3.334 +
   3.335  	a = atomic_action_new(ACTION_MAKE_DIRS);
   3.336 -	a->args.path = strdup(path);
   3.337 -	a->args.u.make_dirs.root = strdup(root);
   3.338 +	a->args.uri = strdup(uri);
   3.339 +	a->args.u.make_dirs.root = strdup(root_uri);
   3.340 +	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   3.341 +
   3.342 +	if (fakeroot)
   3.343 +		free(fakeroot);
   3.344 +
   3.345 +	return 0;
   3.346 +}
   3.347 +
   3.348 +RAZOR_EXPORT int
   3.349 +razor_atomic_remove(struct razor_atomic *atomic, const char *uri)
   3.350 +{
   3.351 +	struct atomic_action *a;
   3.352 +
   3.353 +	razor_atomic_set_toplevel_from_uri(atomic, uri);
   3.354 +
   3.355 +	if (razor_atomic_in_error_state(atomic))
   3.356 +		return -1;
   3.357 +
   3.358 +	a = atomic_action_new(ACTION_REMOVE);
   3.359 +	a->args.uri = strdup(uri);
   3.360  	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   3.361  
   3.362  	return 0;
   3.363  }
   3.364  
   3.365  RAZOR_EXPORT int
   3.366 -razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   3.367 +razor_atomic_rename_file(struct razor_atomic *atomic, const char *old_uri,
   3.368 +			 const char *new_uri)
   3.369  {
   3.370  	struct atomic_action *a;
   3.371  
   3.372 -	razor_atomic_set_toplevel_from_path(atomic, path);
   3.373 +	razor_atomic_set_toplevel_from_uri(atomic, new_uri);
   3.374  
   3.375  	if (razor_atomic_in_error_state(atomic))
   3.376  		return -1;
   3.377  
   3.378 -	a = atomic_action_new(ACTION_REMOVE);
   3.379 -	a->args.path = strdup(path);
   3.380 +	a = atomic_action_new(ACTION_MOVE);
   3.381 +	a->args.uri = strdup(old_uri);
   3.382 +	a->args.u.move.dest = strdup(new_uri);
   3.383  	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   3.384  
   3.385  	return 0;
   3.386  }
   3.387  
   3.388  RAZOR_EXPORT int
   3.389 -razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   3.390 -			 const char *newpath)
   3.391 -{
   3.392 -	struct atomic_action *a;
   3.393 -
   3.394 -	razor_atomic_set_toplevel_from_path(atomic, newpath);
   3.395 -
   3.396 -	if (razor_atomic_in_error_state(atomic))
   3.397 -		return -1;
   3.398 -
   3.399 -	a = atomic_action_new(ACTION_MOVE);
   3.400 -	a->args.path = strdup(oldpath);
   3.401 -	a->args.u.move.dest = strdup(newpath);
   3.402 -	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   3.403 -
   3.404 -	return 0;
   3.405 -}
   3.406 -
   3.407 -RAZOR_EXPORT int
   3.408 -razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   3.409 +razor_atomic_create_dir(struct razor_atomic *atomic, const char *uri,
   3.410  			mode_t mode)
   3.411  {
   3.412  	struct atomic_action *a;
   3.413  
   3.414 -	razor_atomic_set_toplevel_from_path(atomic, dirname);
   3.415 +	razor_atomic_set_toplevel_from_uri(atomic, uri);
   3.416  
   3.417  	if (razor_atomic_in_error_state(atomic))
   3.418  		return -1;
   3.419  
   3.420  	a = atomic_action_new(ACTION_CREATE_DIR);
   3.421 -	a->args.path = strdup(dirname);
   3.422 +	a->args.uri = strdup(uri);
   3.423  	a->args.u.create_dir.mode = mode;
   3.424  	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   3.425  
   3.426 @@ -434,12 +258,12 @@
   3.427  
   3.428  RAZOR_EXPORT int
   3.429  razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   3.430 -			    const char *path)
   3.431 +			    const char *uri)
   3.432  {
   3.433  #if HAVE_SYMLINK
   3.434  	struct atomic_action *a;
   3.435  
   3.436 -	razor_atomic_set_toplevel_from_path(atomic, path);
   3.437 +	razor_atomic_set_toplevel_from_uri(atomic, uri);
   3.438  #endif
   3.439  
   3.440  	if (razor_atomic_in_error_state(atomic))
   3.441 @@ -447,7 +271,7 @@
   3.442  
   3.443  #if HAVE_SYMLINK
   3.444  	a = atomic_action_new(ACTION_CREATE_SYMLINK);
   3.445 -	a->args.path = strdup(path);
   3.446 +	a->args.uri = strdup(uri);
   3.447  	a->args.u.create_symlink.target = strdup(target);
   3.448  	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
   3.449  
   3.450 @@ -462,28 +286,27 @@
   3.451  }
   3.452  
   3.453  RAZOR_EXPORT int
   3.454 -razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   3.455 +razor_atomic_create_file(struct razor_atomic *atomic, const char *uri,
   3.456                           mode_t mode)
   3.457  {
   3.458  	int fd;
   3.459  	struct atomic_action *a;
   3.460  	char *tmpnam;
   3.461  
   3.462 -	razor_atomic_set_toplevel_from_path(atomic, filename);
   3.463 +	razor_atomic_set_toplevel_from_uri(atomic, uri);
   3.464  
   3.465  	if (razor_atomic_in_error_state(atomic))
   3.466  		return -1;
   3.467  
   3.468  	tmpnam = atomic_action_attic_tmpnam(atomic);
   3.469 -	fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   3.470 -		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   3.471 +	fd = razor_uri_open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   3.472 +			    mode & (S_IRWXU | S_IRWXG | S_IRWXO),
   3.473 +			    &atomic->error);
   3.474  
   3.475 -	if (fd == -1)
   3.476 -		atomic->error = razor_error_new_posix(filename);
   3.477 -	else {
   3.478 +	if (fd >= 0) {
   3.479  		a = atomic_action_new(ACTION_MOVE);
   3.480 -		a->args.path = tmpnam;
   3.481 -		a->args.u.move.dest = strdup(filename);
   3.482 +		a->args.uri = tmpnam;
   3.483 +		a->args.u.move.dest = strdup(uri);
   3.484  		atomic->actions = atomic_action_list_prepend(atomic->actions,
   3.485  							     a);
   3.486  	}
     4.1 --- a/librazor/atomic-ktm.c	Sat Jun 11 17:56:48 2016 +0100
     4.2 +++ b/librazor/atomic-ktm.c	Mon Jul 04 10:48:18 2016 +0100
     4.3 @@ -24,10 +24,8 @@
     4.4  #include <windows.h>
     4.5  #include <stdio.h>
     4.6  #include <limits.h>
     4.7 +#include <unistd.h>
     4.8  #include <errno.h>
     4.9 -#include <unistd.h>
    4.10 -#include <fcntl.h>
    4.11 -#include <sys/stat.h>
    4.12  #include <string.h>
    4.13  #include <assert.h>
    4.14  #include <wchar.h>
     5.1 --- a/librazor/atomic-none.c	Sat Jun 11 17:56:48 2016 +0100
     5.2 +++ b/librazor/atomic-none.c	Mon Jul 04 10:48:18 2016 +0100
     5.3 @@ -244,8 +244,8 @@
     5.4  	if (razor_atomic_in_error_state(atomic))
     5.5  		return -1;
     5.6  
     5.7 -	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
     5.8 -		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
     5.9 +	fd = razor_uri_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
    5.10 +			    mode & (S_IRWXU | S_IRWXG | S_IRWXO));
    5.11  
    5.12  	if (fd == -1)
    5.13  		atomic->error = razor_error_new_posix(filename);
     6.1 --- a/librazor/atomic.c	Sat Jun 11 17:56:48 2016 +0100
     6.2 +++ b/librazor/atomic.c	Mon Jul 04 10:48:18 2016 +0100
     6.3 @@ -1,5 +1,5 @@
     6.4  /*
     6.5 - * Copyright (C) 2011-2012  J. Ali Harlow <ali@juiblex.co.uk>
     6.6 + * Copyright (C) 2011-2012, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     6.7   *
     6.8   * This program is free software; you can redistribute it and/or modify
     6.9   * it under the terms of the GNU General Public License as published by
    6.10 @@ -23,9 +23,6 @@
    6.11  #include <limits.h>
    6.12  #include <errno.h>
    6.13  #include <unistd.h>
    6.14 -#include <sys/types.h>
    6.15 -#include <sys/stat.h>
    6.16 -#include <fcntl.h>
    6.17  #include <string.h>
    6.18  #include <assert.h>
    6.19  
    6.20 @@ -81,8 +78,15 @@
    6.21  razor_atomic_propagate_error(struct razor_atomic *atomic,
    6.22  			     struct razor_error *error, const char *summary)
    6.23  {
    6.24 -	if (!atomic->error)
    6.25 -		atomic->error = razor_error_dup(error, summary);
    6.26 +	if (!atomic->error) {
    6.27 +		if (!summary) {
    6.28 +			atomic->error = error;
    6.29 +			return;
    6.30 +		} else
    6.31 +			atomic->error = razor_error_dup(error, summary);
    6.32 +	}
    6.33 +
    6.34 +	razor_error_free(error);
    6.35  }
    6.36  
    6.37  RAZOR_EXPORT int
     7.1 --- a/librazor/dump.c	Sat Jun 11 17:56:48 2016 +0100
     7.2 +++ b/librazor/dump.c	Mon Jul 04 10:48:18 2016 +0100
     7.3 @@ -1,5 +1,5 @@
     7.4  /*
     7.5 - * Copyright (C) 2014  J. Ali Harlow <ali@juiblex.co.uk>
     7.6 + * Copyright (C) 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     7.7   *
     7.8   * This program is free software; you can redistribute it and/or modify
     7.9   * it under the terms of the GNU General Public License as published by
    7.10 @@ -356,11 +356,11 @@
    7.11  }
    7.12  
    7.13  RAZOR_EXPORT int
    7.14 -razor_dump_database(FILE *fp, const char *root, const char *filename,
    7.15 +razor_dump_database(FILE *fp, const char *root_uri, const char *filename,
    7.16  		    struct razor_error **error)
    7.17  {
    7.18  	int i;
    7.19 -	char *s, *path, *data;
    7.20 +	char *s, *uri, *data;
    7.21  	struct array pool = { 0, };
    7.22  	struct array string_pool = { 0, };
    7.23  	struct array file_string_pool = { 0, };
    7.24 @@ -377,11 +377,14 @@
    7.25  	if (!filename)
    7.26  		filename = "system.rzdb";
    7.27  
    7.28 -	s = razor_concat(razor_get_database_path(), "/", filename, NULL);
    7.29 -	path = razor_path_add_root(s, root);
    7.30 -	free(s);
    7.31 -	contents = razor_file_get_contents(path, &length, 0, error);
    7.32 -	free(path);
    7.33 +	uri = razor_resolve_database_file(root_uri, filename, error);
    7.34 +
    7.35 +	if (!uri)
    7.36 +		return -1;
    7.37 +
    7.38 +	contents = razor_uri_get_contents(uri, &length, 0, error);
    7.39 +
    7.40 +	free(uri);
    7.41  
    7.42  	if (!contents)
    7.43  		return -1;
    7.44 @@ -482,7 +485,7 @@
    7.45  
    7.46  	fprintf(fp, "%05lX EOF\n", (unsigned long)n);
    7.47  
    7.48 -	razor_file_free_contents(contents, length);
    7.49 +	razor_uri_free_contents(contents, length);
    7.50  
    7.51  	return 0;
    7.52  }
     8.1 --- a/librazor/path.c	Sat Jun 11 17:56:48 2016 +0100
     8.2 +++ b/librazor/path.c	Mon Jul 04 10:48:18 2016 +0100
     8.3 @@ -1,5 +1,5 @@
     8.4  /*
     8.5 - * Copyright (C) 2014  J. Ali Harlow <ali@juiblex.co.uk>
     8.6 + * Copyright (C) 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     8.7   *
     8.8   * This program is free software; you can redistribute it and/or modify
     8.9   * it under the terms of the GNU General Public License as published by
    8.10 @@ -19,78 +19,10 @@
    8.11  #include "config.h"
    8.12  #include <stdlib.h>
    8.13  #include <string.h>
    8.14 +#include <ctype.h>
    8.15  #include "razor.h"
    8.16  #include "razor-internal.h"
    8.17 -
    8.18 -/**
    8.19 - * razor_path_add_root:
    8.20 - *
    8.21 - * Adds a root to a path. path must be an absolute pathname. In POSIX
    8.22 - * environments this is equivalent to the concationation of root and path.
    8.23 - * In Microsoft Windows an adjustment may need to be made for a drive letter
    8.24 - * in path (which will be dropped).
    8.25 - *
    8.26 - * Returns: The new pathname.
    8.27 - **/
    8.28 -RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root)
    8.29 -{
    8.30 -	if (root && *root)
    8.31 -		return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL);
    8.32 -	else
    8.33 -		return strdup(path);
    8.34 -}
    8.35 -
    8.36 -#if 0
    8.37 -
    8.38 -/*
    8.39 - * This should work, but for some reason PathCreateFromUrlW()
    8.40 - * treats the percent-encoded bytes as being in CP 850 rather
    8.41 - * than UTF-8 as expected even if we set the codepage.
    8.42 - */
    8.43 -RAZOR_EXPORT char *razor_path_from_url(const char *url)
    8.44 -{
    8.45 -	UINT saved_cp;
    8.46 -	HRESULT result;
    8.47 -	DWORD len = MAX_PATH;
    8.48 -	wchar_t *url16;
    8.49 -	wchar_t path16[MAX_PATH];
    8.50 -	char *path;
    8.51 -
    8.52 -	url16 = razor_utf8_to_utf16(url, -1);
    8.53 -
    8.54 -	saved_cp = GetConsoleCP();
    8.55 -	SetConsoleCP(CP_UTF8);
    8.56 -
    8.57 -	result = PathCreateFromUrlW(url16, path16, &len, NULL);
    8.58 -
    8.59 -	SetConsoleCP(saved_cp);
    8.60 -
    8.61 -	if (result == S_OK)
    8.62 -		path = razor_utf16_to_utf8(path16, len);
    8.63 -	else
    8.64 -		path = NULL;
    8.65 -
    8.66 -	free(url16);
    8.67 -
    8.68 -	return path;
    8.69 -}
    8.70 -
    8.71 -#else
    8.72 -
    8.73 -#ifdef MSWIN_API
    8.74 -static int is_ascii_letter(char c)
    8.75 -{
    8.76 -	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
    8.77 -}
    8.78 -#endif
    8.79 -
    8.80 -static int xdigit_value(char c)
    8.81 -{
    8.82 -	if (c >= '0' && c <= '9')
    8.83 -		return c - '0';
    8.84 -	else
    8.85 -		return (c | 0x20) - 'a' + 10;
    8.86 -}
    8.87 +#include "uri.h"
    8.88  
    8.89  static int valid_unicode(unsigned unicode)
    8.90  {
    8.91 @@ -101,54 +33,74 @@
    8.92  	return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000);
    8.93  }
    8.94  
    8.95 -RAZOR_EXPORT char *razor_path_from_url(const char *url)
    8.96 +char *razor_path_from_parsed_uri(const struct razor_uri *ru,
    8.97 +  struct razor_error **error)
    8.98  {
    8.99  	int continuation_bytes = 0;
   8.100 -	char *path, *p;
   8.101 +	char *path, *p, *s, *uri;
   8.102  	unsigned char c;
   8.103  	unsigned unicode;
   8.104  
   8.105 -	if (strncmp(url, "file://", 7) == 0)
   8.106 -		url += 7;
   8.107 -	else
   8.108 +	if (!ru->scheme) {
   8.109 +		uri = razor_uri_recompose(ru);
   8.110 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   8.111 +				RAZOR_GENERAL_ERROR_BAD_URI, uri,
   8.112 +				"URI does not include a scheme");
   8.113 +		free(uri);
   8.114  		return NULL;
   8.115 +	}
   8.116  
   8.117 -	if (strncmp(url, "localhost/", 10) == 0)
   8.118 -		url += 9;
   8.119 -	else if (strncmp(url, "/", 1) != 0)
   8.120 +	if (strcmp(ru->scheme, "file")) {
   8.121 +		uri = razor_uri_recompose(ru);
   8.122 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   8.123 +				RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri,
   8.124 +				"Not a file URI");
   8.125 +		free(uri);
   8.126  		return NULL;
   8.127 +	}
   8.128  
   8.129 +	if (ru->host && *ru->host && strcmp(ru->host, "localhost") ||
   8.130 +	    ru->userinfo || ru->port) {
   8.131 +		uri = razor_uri_recompose(ru);
   8.132 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   8.133 +				RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri,
   8.134 +				"URI refers to a non-local file");
   8.135 +		free(uri);
   8.136 +		return NULL;
   8.137 +	}
   8.138 +
   8.139 +	s = ru->path;
   8.140  #ifdef MSWIN_API
   8.141  	/*
   8.142 -	 * Under MS-Windows, file:///c:/xxx maps to c:/xxx
   8.143 +	 * Under MS-Windows, a path of /c:/xxx maps to c:/xxx
   8.144  	 * Note that PathCreateFromUrl converts / to \ as well.
   8.145  	 */
   8.146 -	if (is_ascii_letter(url[1]) && url[2] == ':' && url[3] == '/')
   8.147 -		url++;
   8.148 +	if (s[0] == '/' && is_alpha(s[1]) && s[2] == ':' && s[3] == '/')
   8.149 +		s++;
   8.150  #endif
   8.151  
   8.152 -	p = path = malloc(strlen(url) + 1);
   8.153 +	p = path = malloc(strlen(s) + 1);
   8.154  
   8.155 -	while(*url) {
   8.156 -		if (*url >= 0x7F || *url < 0x20) {
   8.157 -			free(path);
   8.158 -			return NULL;
   8.159 -		} else if (*url != '%') {
   8.160 -			if (continuation_bytes) {
   8.161 -				free(path);
   8.162 -				return NULL;
   8.163 -			} else
   8.164 -				*p++ = *url++;
   8.165 -		} else if (isxdigit(url[1]) && isxdigit(url[2])) {
   8.166 -			c = xdigit_value(url[1]) * 16 + xdigit_value(url[2]);
   8.167 -			if (c == '/') {
   8.168 -				free(path);
   8.169 -				return NULL;
   8.170 -			} else if (!continuation_bytes) {
   8.171 -				if (c >= 0xF5 || c == 0xC0 || c == 0xC1) {
   8.172 -					free(path);
   8.173 -					return NULL;
   8.174 -				} else if (c >= 0xF0) {
   8.175 +	while (*s) {
   8.176 +		if (*s >= 0x7F || *s < 0x20)
   8.177 +			break;
   8.178 +		else if (*s != '%') {
   8.179 +			if (continuation_bytes)
   8.180 +				break;
   8.181 +			else
   8.182 +				*p++ = *s++;
   8.183 +		} else {
   8.184 +			c = pchar_get_char(s);
   8.185 +#ifdef MSWIN_API
   8.186 +			if (c == '/' || c == '\\')
   8.187 +#else
   8.188 +			if (c == '/')
   8.189 +#endif
   8.190 +				break;
   8.191 +			else if (!continuation_bytes) {
   8.192 +				if (c >= 0xF5 || c == 0xC0 || c == 0xC1)
   8.193 +					break;
   8.194 +				else if (c >= 0xF0) {
   8.195  					unicode = c & 7;
   8.196  					continuation_bytes = 3;
   8.197  				} else if (c >= 0xE0) {
   8.198 @@ -158,29 +110,28 @@
   8.199  					unicode = c & 1;
   8.200  					continuation_bytes = 1;
   8.201  				}
   8.202 -			} else if ((c & 0xC0) != 0x80) {
   8.203 -				free(path);
   8.204 -				return NULL;
   8.205 -			} else {
   8.206 +			} else if ((c & 0xC0) != 0x80)
   8.207 +				break;
   8.208 +			else {
   8.209  				unicode <<= 6;
   8.210  				unicode |= (c & 0x3F);
   8.211  
   8.212  				if (!--continuation_bytes &&
   8.213 -				    !valid_unicode(unicode)) {
   8.214 -					free(path);
   8.215 -					return NULL;
   8.216 -				}
   8.217 +				    !valid_unicode(unicode))
   8.218 +					break;
   8.219  			}
   8.220  
   8.221  			*p++ = c;
   8.222 -			url += 3;
   8.223 -		} else {
   8.224 -			free(path);
   8.225 -			return NULL;
   8.226 +			s += 3;
   8.227  		}
   8.228  	}
   8.229  
   8.230 -	if (continuation_bytes) {
   8.231 +	if (*s || continuation_bytes) {
   8.232 +		uri = razor_uri_recompose(ru);
   8.233 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   8.234 +				RAZOR_GENERAL_ERROR_BAD_URI,
   8.235 +				uri, "Illegal character in file URI path");
   8.236 +		free(uri);
   8.237  		free(path);
   8.238  		return NULL;
   8.239  	}
   8.240 @@ -190,4 +141,72 @@
   8.241  	return realloc(path, p - path);
   8.242  }
   8.243  
   8.244 -#endif	/* 0 */
   8.245 +RAZOR_EXPORT char *razor_path_from_uri(const char *uri,
   8.246 +  struct razor_error **error)
   8.247 +{
   8.248 +	struct razor_uri ru;
   8.249 +	char *path;
   8.250 +
   8.251 +	if (razor_uri_parse(&ru, uri, error))
   8.252 +		return NULL;
   8.253 +
   8.254 +	path = razor_path_from_parsed_uri(&ru, error);
   8.255 +
   8.256 +	razor_uri_destroy(&ru);
   8.257 +
   8.258 +	return path;
   8.259 +}
   8.260 +
   8.261 +RAZOR_EXPORT char *razor_path_to_uri(const char *path)
   8.262 +{
   8.263 +	char *uri, *p;
   8.264 +
   8.265 +	uri = malloc(6 + 3 * strlen(path) + 1);
   8.266 +
   8.267 +	strcpy(uri, "file:");
   8.268 +
   8.269 +	p = uri + 5;
   8.270 +
   8.271 +#ifdef MSWIN_API
   8.272 +	/*
   8.273 +	 * Under MS-Windows, c:/xxx maps to a path of /c:/xxx
   8.274 +	 */
   8.275 +	if (is_alpha(path[0]) && path[1] == ':' && path[2] == '/')
   8.276 +		*p++ = '/';
   8.277 +#endif
   8.278 +
   8.279 +	while(*path) {
   8.280 +		if (*path == '/' || is_unreserved(*path) ||
   8.281 +		    is_sub_delim(*path) || *path == ':' || *path == '@')
   8.282 +			*p++ = *path;
   8.283 +#ifdef MSWIN_API
   8.284 +		else if (*path == '\\')
   8.285 +			*p++ = '/';
   8.286 +#endif
   8.287 +		else {
   8.288 +			*p++ = '%';
   8.289 +			*p++ = "0123456789ABCDEF"[(*(unsigned char *)path)/16];
   8.290 +			*p++ = "0123456789ABCDEF"[(*(unsigned char *)path)%16];
   8.291 +		}
   8.292 +		path++;
   8.293 +	}
   8.294 +	*p++ = '\0';
   8.295 +
   8.296 +	return realloc(uri, p - uri);
   8.297 +}
   8.298 +
   8.299 +RAZOR_EXPORT char *
   8.300 +razor_path_relative_to_uri(const char *uri, const char *path,
   8.301 +			   struct razor_error **error)
   8.302 +{
   8.303 +	char *rel_uri, *result;
   8.304 +
   8.305 +	/* Strictly wrong if uri isn't a file URI, but probably okay */
   8.306 +	rel_uri = razor_path_to_uri(path);
   8.307 +
   8.308 +	result = razor_resolve_uri_root(uri, rel_uri + 5, 1, error);
   8.309 +
   8.310 +	free(rel_uri);
   8.311 +
   8.312 +	return result;
   8.313 +}
     9.1 --- a/librazor/razor-internal.h	Sat Jun 11 17:56:48 2016 +0100
     9.2 +++ b/librazor/razor-internal.h	Mon Jul 04 10:48:18 2016 +0100
     9.3 @@ -1,7 +1,7 @@
     9.4  /*
     9.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     9.6   * Copyright (C) 2008  Red Hat, Inc
     9.7 - * Copyright (C) 2009, 2011-2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
     9.8 + * Copyright (C) 2009, 2011-2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     9.9   *
    9.10   * This program is free software; you can redistribute it and/or modify
    9.11   * it under the terms of the GNU General Public License as published by
    9.12 @@ -42,6 +42,9 @@
    9.13  #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    9.14  #define PADDING(value, base) (-(value) & (base - 1))
    9.15  #define ALIGN(value, base) ((value) + PADDING(value, base))
    9.16 +
    9.17 +#define str_has_prefix(s, prefix)	(!strncmp(s, prefix, strlen(prefix)))
    9.18 +
    9.19  void *zalloc(size_t size);
    9.20  
    9.21  struct razor_set_section {
    9.22 @@ -181,7 +184,7 @@
    9.23  };
    9.24  
    9.25  int
    9.26 -razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive);
    9.27 +razor_set_acquire_lock(struct razor_set *set, const char *path, int exclusive);
    9.28  
    9.29  struct razor_entry *
    9.30  razor_set_find_entry(struct razor_set *set,
    9.31 @@ -206,7 +209,72 @@
    9.32  		   ssize_t len, int arg1);
    9.33  
    9.34  int razor_run_script(const char *root, enum razor_property_flags script,
    9.35 -		     const char *program, const char *body, int arg1);
    9.36 +		     const char *program, const char *body, int arg1,
    9.37 +		     struct razor_error **error);
    9.38 +
    9.39 +/* URI functions */
    9.40 +
    9.41 +struct razor_uri {
    9.42 +	char *scheme;
    9.43 +	char *userinfo;
    9.44 +	char *host;
    9.45 +	char *port;
    9.46 +	char *path;
    9.47 +	char *query;
    9.48 +	char *fragment;
    9.49 +};
    9.50 +
    9.51 +void razor_uri_destroy(struct razor_uri *ru);
    9.52 +int razor_uri_parse_uri(struct razor_uri *ru, const char *uri, int absolute,
    9.53 +			struct razor_error **error);
    9.54 +int razor_uri_parse_relative_ref(struct razor_uri *ru, const char *uri,
    9.55 +				 struct razor_error **error);
    9.56 +int razor_uri_parse(struct razor_uri *ru, const char *uri,
    9.57 +		    struct razor_error **error);
    9.58 +void razor_uri_normalize(struct razor_uri *ru);
    9.59 +char *razor_uri_get_authority(const struct razor_uri *ru) RAZOR_MALLOC;
    9.60 +char *razor_uri_recompose(const struct razor_uri *ru) RAZOR_MALLOC;
    9.61 +void razor_uri_resolve(struct razor_uri *T, const struct razor_uri *base,
    9.62 +		       const struct razor_uri *R);
    9.63 +
    9.64 +char *razor_resolve_uri_root(const char *root_uri, const char *relative_uri,
    9.65 +			     int is_relative, struct razor_error **error)
    9.66 +      RAZOR_MALLOC;
    9.67 +
    9.68 +int razor_file_mkdir(const char *path, mode_t mode, struct razor_error **error);
    9.69 +int razor_file_unlink(const char *path, struct razor_error **error);
    9.70 +int razor_file_open(const char *path, int flags, mode_t mode,
    9.71 +		    struct razor_error **error);
    9.72 +int razor_file_move(const char *path, const char *dest,
    9.73 +		    struct razor_error **error);
    9.74 +void *razor_file_get_contents(const char *path, size_t *length, int _private,
    9.75 +			      struct razor_error **error);
    9.76 +int razor_file_free_contents(void *addr, size_t length);
    9.77 +int razor_file_is_directory(const char *path, struct razor_error **error);
    9.78 +char *razor_file_mkdtemp_near(const char *path, const char *_template,
    9.79 +			      struct razor_error **error);
    9.80 +void *razor_file_opendir(const char *path, struct razor_error **error);
    9.81 +char *razor_file_readdir(void *dir, struct razor_error **error);
    9.82 +int razor_file_closedir(void *dir, struct razor_error **error);
    9.83 +
    9.84 +int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error);
    9.85 +int razor_uri_unlink(const char *uri, struct razor_error **error);
    9.86 +int razor_uri_open(const char *uri, int flags, mode_t mode,
    9.87 +		   struct razor_error **error);
    9.88 +int razor_uri_move(const char *uri, const char *dest,
    9.89 +		   struct razor_error **error);
    9.90 +int razor_uri_is_directory(const char *uri, struct razor_error **error);
    9.91 +char *razor_uri_mkdtemp_near(const char *uri, const char *template,
    9.92 +			     struct razor_error **error) RAZOR_MALLOC;
    9.93 +void *razor_uri_opendir(const char *uri, struct razor_error **error);
    9.94 +char *razor_uri_readdir(void *dir, struct razor_error **error) RAZOR_MALLOC;
    9.95 +int razor_uri_closedir(void *dir, struct razor_error **error);
    9.96 +void *razor_uri_get_contents(const char *uri, size_t *length, int private,
    9.97 +			     struct razor_error **error);
    9.98 +int razor_uri_free_contents(void *addr, size_t length);
    9.99 +
   9.100 +char *razor_path_from_parsed_uri(const struct razor_uri *ru,
   9.101 +  struct razor_error **error);
   9.102  
   9.103  /* Utility functions */
   9.104  
   9.105 @@ -216,16 +284,6 @@
   9.106  			       va_list args);
   9.107  void razor_rpm_get_details_varg(struct razor_rpm *rpm, va_list args);
   9.108  
   9.109 -int razor_create_dir(const char *root, const char *path);
   9.110 -int razor_remove(const char *path);
   9.111 -int razor_write(int fd, const void *data, size_t size);
   9.112 -
   9.113 -void *
   9.114 -razor_file_get_contents(const char *filename, size_t *length, int private,
   9.115 -			struct razor_error **error);
   9.116 -int razor_file_free_contents(void *addr, size_t length);
   9.117 -
   9.118 -
   9.119  typedef int (*razor_compare_with_data_func_t)(const void *p1,
   9.120  					      const void *p,
   9.121  					      void *data);
   9.122 @@ -267,6 +325,10 @@
   9.123  	if (error) \
   9.124  		*(error) = razor_error_new_posix(object); \
   9.125  	else
   9.126 +#define razor_set_error(error, domain, code, object, str) \
   9.127 +	if (error) \
   9.128 +		*(error) = razor_error_new_str(domain, code, object, str); \
   9.129 +	else
   9.130  
   9.131  #ifdef MSWIN_API
   9.132  struct razor_error *razor_error_new_mswin(const wchar_t *object, DWORD error);
   9.133 @@ -312,7 +374,7 @@
   9.134  		ACTION_MOVE,
   9.135  	} type;
   9.136  	struct {
   9.137 -		char *path;
   9.138 +		char *uri;
   9.139  		union atomic_action_args {
   9.140  			struct {
   9.141  				char *root;
   9.142 @@ -359,6 +421,9 @@
   9.143  };
   9.144  #endif
   9.145  
   9.146 +char *razor_resolve_database_file(const char *root_uri, const char *filename,
   9.147 +				  struct razor_error **error);
   9.148 +
   9.149  int razor_allow_all_root_names(void);
   9.150  int razor_valid_root_name(const char *name);
   9.151  
    10.1 --- a/librazor/razor.c	Sat Jun 11 17:56:48 2016 +0100
    10.2 +++ b/librazor/razor.c	Mon Jul 04 10:48:18 2016 +0100
    10.3 @@ -1,7 +1,7 @@
    10.4  /*
    10.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    10.6   * Copyright (C) 2008  Red Hat, Inc
    10.7 - * Copyright (C) 2009-2012  J. Ali Harlow <ali@juiblex.co.uk>
    10.8 + * Copyright (C) 2009-2012, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    10.9   *
   10.10   * This program is free software; you can redistribute it and/or modify
   10.11   * it under the terms of the GNU General Public License as published by
   10.12 @@ -28,10 +28,8 @@
   10.13  #include <stdio.h>
   10.14  #include <stdarg.h>
   10.15  #include <string.h>
   10.16 -#include <sys/types.h>
   10.17 -#include <sys/stat.h>
   10.18 +#include <fcntl.h>
   10.19  #include <unistd.h>
   10.20 -#include <fcntl.h>
   10.21  #include <errno.h>
   10.22  #include <ctype.h>
   10.23  #include <fnmatch.h>
   10.24 @@ -140,7 +138,7 @@
   10.25  };
   10.26  
   10.27  RAZOR_EXPORT int
   10.28 -razor_set_bind_sections(struct razor_set *set, const char *filename,
   10.29 +razor_set_bind_sections(struct razor_set *set, const char *uri,
   10.30  			enum razor_set_flags flags, struct razor_error **error)
   10.31  {
   10.32  	struct razor_set_section *s, *sections;
   10.33 @@ -156,9 +154,9 @@
   10.34  		return -1;
   10.35  	}
   10.36  
   10.37 -	file->header = razor_file_get_contents(filename, &file->size,
   10.38 -					       flags & RAZOR_SET_PRIVATE,
   10.39 -					       error);
   10.40 +	file->header = razor_uri_get_contents(uri, &file->size,
   10.41 +					      flags & RAZOR_SET_PRIVATE,
   10.42 +					      error);
   10.43  	if (!file->header) {
   10.44  		free(file);
   10.45  		return -1;
   10.46 @@ -178,9 +176,8 @@
   10.47  		reason = NULL;
   10.48  
   10.49  	if (reason) {
   10.50 -		razor_set_error(error, RAZOR_GENERAL_ERROR, code, filename,
   10.51 -				reason);
   10.52 -		razor_file_free_contents(file->header, file->size);
   10.53 +		razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason);
   10.54 +		razor_uri_free_contents(file->header, file->size);
   10.55  		free(file);
   10.56  		return -1;
   10.57  	}
   10.58 @@ -220,7 +217,7 @@
   10.59  }
   10.60  
   10.61  RAZOR_EXPORT struct razor_set *
   10.62 -razor_set_open(const char *filename, enum razor_set_flags flags,
   10.63 +razor_set_open(const char *uri, enum razor_set_flags flags,
   10.64  	       struct razor_error **error)
   10.65  {
   10.66  	struct razor_set *set;
   10.67 @@ -234,7 +231,7 @@
   10.68  
   10.69  	set->lock_fd = -1;
   10.70  	set->ref_count = 1;
   10.71 -	if (razor_set_bind_sections(set, filename, flags, error)) {
   10.72 +	if (razor_set_bind_sections(set, uri, flags, error)) {
   10.73  		free(set);
   10.74  		return NULL;
   10.75  	}
   10.76 @@ -242,18 +239,18 @@
   10.77  }
   10.78  
   10.79  int
   10.80 -razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
   10.81 +razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive)
   10.82  {
   10.83  	int fd;
   10.84  	assert(set != NULL);
   10.85  
   10.86 -	if (path) {
   10.87 -		fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
   10.88 +	if (uri) {
   10.89 +		fd = razor_uri_open(uri, O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
   10.90 +				    0666, NULL);
   10.91  		if (fd < 0)
   10.92  			return -1;
   10.93 -	} else {
   10.94 +	} else
   10.95  		fd = -1;
   10.96 -	}
   10.97  
   10.98  #ifdef MSWIN_API
   10.99  	DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
  10.100 @@ -310,12 +307,12 @@
  10.101  	} else {
  10.102  		for (file = set->mapped_files; file != NULL; file = next) {
  10.103  			next = file->next;
  10.104 -			razor_file_free_contents(file->header, file->size);
  10.105 +			razor_uri_free_contents(file->header, file->size);
  10.106  			free(file);
  10.107  		}
  10.108  	}
  10.109  
  10.110 -	razor_set_aquire_lock(set, NULL, 0);
  10.111 +	razor_set_acquire_lock(set, NULL, 0);
  10.112  	free(set);
  10.113  }
  10.114  
  10.115 @@ -390,11 +387,11 @@
  10.116  
  10.117  RAZOR_EXPORT int
  10.118  razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
  10.119 -		const char *filename, uint32_t sections)
  10.120 +		const char *uri, uint32_t sections)
  10.121  {
  10.122  	int h;
  10.123  
  10.124 -	h = razor_atomic_create_file(atomic, filename,
  10.125 +	h = razor_atomic_create_file(atomic, uri,
  10.126  				     S_IRWXU | S_IRWXG | S_IRWXO);
  10.127  	if (h < 0)
  10.128  		return -1;
  10.129 @@ -636,6 +633,7 @@
  10.130  	struct environment env;
  10.131  	struct list *link;
  10.132  	const char *prefix;
  10.133 +	struct razor_error *tmp_error = NULL;
  10.134  
  10.135  	if (stage & RAZOR_STAGE_SCRIPTS) {
  10.136  		environment_init(&env);
  10.137 @@ -658,7 +656,12 @@
  10.138  					  RAZOR_DETAIL_LAST);
  10.139  
  10.140  		retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program,
  10.141 -					  script, install_count);
  10.142 +					  script, install_count, &tmp_error);
  10.143 +
  10.144 +		if (retval < 0) {
  10.145 +			razor_atomic_propagate_error(atomic, tmp_error, NULL);
  10.146 +			tmp_error = NULL;
  10.147 +		}
  10.148  	}
  10.149  
  10.150  	if (!retval && (stage & RAZOR_STAGE_FILES)) {
  10.151 @@ -690,7 +693,12 @@
  10.152  					  RAZOR_DETAIL_LAST);
  10.153  
  10.154  		retval |= razor_run_script(root, RAZOR_PROPERTY_POSTUN, program,
  10.155 -					   script, install_count);
  10.156 +					   script, install_count, &tmp_error);
  10.157 +
  10.158 +		if (retval < 0) {
  10.159 +			razor_atomic_propagate_error(atomic, tmp_error, NULL);
  10.160 +			tmp_error = NULL;
  10.161 +		}
  10.162  	}
  10.163  
  10.164  	if (stage & RAZOR_STAGE_SCRIPTS) {
    11.1 --- a/librazor/razor.h.in	Sat Jun 11 17:56:48 2016 +0100
    11.2 +++ b/librazor/razor.h.in	Mon Jul 04 10:48:18 2016 +0100
    11.3 @@ -1,7 +1,7 @@
    11.4  /*
    11.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    11.6   * Copyright (C) 2008  Red Hat, Inc
    11.7 - * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
    11.8 + * Copyright (C) 2009, 2011, 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    11.9   *
   11.10   * This program is free software; you can redistribute it and/or modify
   11.11   * it under the terms of the GNU General Public License as published by
   11.12 @@ -23,7 +23,7 @@
   11.13  
   11.14  #include <stdio.h>
   11.15  #include <stdint.h>
   11.16 -#include <sys/types.h>
   11.17 +#include <sys/stat.h>
   11.18  
   11.19  /* GCC extensions */
   11.20  #if defined(__GNUC__)
   11.21 @@ -130,6 +130,10 @@
   11.22  		*(dest) = razor_error_dup(src, summary); \
   11.23  	else
   11.24  
   11.25 +#define razor_error_matches(error, domain, code) \
   11.26 +	((error) && razor_error_get_domain(error) == (domain) && \
   11.27 +	 razor_error_get_code(error) == (code))
   11.28 +
   11.29  #define RAZOR_ERROR_DOMAIN(i1,i2,i3,c) \
   11.30  	(((i1)&0xff)<<24|((i2)&0xff)<<16|((i3)&0xff)<<8|(c)&0xff)
   11.31  
   11.32 @@ -145,6 +149,8 @@
   11.33  	RAZOR_GENERAL_ERROR_DATABASE_EXISTS,
   11.34  	RAZOR_GENERAL_ERROR_DATABASE_LOCKED,
   11.35  	RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
   11.36 +	RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
   11.37 +	RAZOR_GENERAL_ERROR_BAD_URI,
   11.38  };
   11.39  
   11.40  int razor_error_get_domain(struct razor_error *error);
   11.41 @@ -195,11 +201,11 @@
   11.42   *
   11.43   * Returns: non-zero on error.
   11.44   **/
   11.45 -int razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
   11.46 -  const char *path);
   11.47 +int razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root_uri,
   11.48 +  const char *uri);
   11.49  int razor_atomic_remove(struct razor_atomic *atomic, const char *path);
   11.50 -int razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   11.51 -			     const char *newpath);
   11.52 +int razor_atomic_rename_file(struct razor_atomic *atomic, const char *old_uri,
   11.53 +			     const char *new_uri);
   11.54  
   11.55  /**
   11.56   * razor_atomic_create_dir
   11.57 @@ -209,8 +215,8 @@
   11.58   *
   11.59   * Returns: non-zero on error.
   11.60   */
   11.61 -int razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   11.62 -  mode_t mode);
   11.63 +int razor_atomic_create_dir(struct razor_atomic *atomic, const char *uri,
   11.64 +			    mode_t mode);
   11.65  
   11.66  /**
   11.67   * razor_atomic_create_symlink
   11.68 @@ -224,7 +230,7 @@
   11.69   * Returns: non-zero on error.
   11.70   */
   11.71  int razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   11.72 -  const char *path);
   11.73 +				const char *uri);
   11.74  /**
   11.75   * razor_atomic_create_file
   11.76   * 
   11.77 @@ -234,16 +240,17 @@
   11.78   * Returns: A handle to be passed to razor_atomic_write() and
   11.79   * razor_atomic_close() or a negative value on error.
   11.80   */
   11.81 -int razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   11.82 -  mode_t mode);
   11.83 +int razor_atomic_create_file(struct razor_atomic *atomic, const char *uri,
   11.84 +			     mode_t mode);
   11.85  int razor_atomic_write(struct razor_atomic *atomic, int handle,
   11.86 -  const void *data, size_t size);
   11.87 +		       const void *data, size_t size);
   11.88  int razor_atomic_close(struct razor_atomic *atomic, int handle);
   11.89  int razor_atomic_sync(struct razor_atomic *atomic, int handle);
   11.90  void razor_atomic_abort(struct razor_atomic *atomic, int domain, int code,
   11.91 -  const char *error_msg);
   11.92 -void razor_atomic_propagate_error(struct razor_atomic *atomic,
   11.93 -  struct razor_error *error, const char *summary);
   11.94 +			const char *error_msg);
   11.95 +void
   11.96 +razor_atomic_propagate_error(struct razor_atomic *atomic,
   11.97 +			     struct razor_error *error, const char *summary);
   11.98  int razor_atomic_in_error_state(struct razor_atomic *atomic);
   11.99  
  11.100  /**
  11.101 @@ -272,7 +279,7 @@
  11.102  struct razor_set *razor_set_create_without_root(void);
  11.103  struct razor_set *razor_set_create(void);
  11.104  struct razor_set *
  11.105 -razor_set_open(const char *filename, enum razor_set_flags flags,
  11.106 +razor_set_open(const char *uri, enum razor_set_flags flags,
  11.107  	       struct razor_error **error);
  11.108  uint32_t razor_set_get_header_version(struct razor_set *set);
  11.109  int razor_set_set_header_version(struct razor_set *set,
  11.110 @@ -283,9 +290,9 @@
  11.111  			       struct razor_atomic *atomic, int handle,
  11.112  			       uint32_t section_mask);
  11.113  int razor_set_write(struct razor_set *set, struct razor_atomic *atomic,
  11.114 -		    const char *filename, uint32_t setions);
  11.115 +		    const char *uri, uint32_t setions);
  11.116  int
  11.117 -razor_set_bind_sections(struct razor_set *set, const char *filename,
  11.118 +razor_set_bind_sections(struct razor_set *set, const char *uri,
  11.119  			enum razor_set_flags flags, struct razor_error **error);
  11.120  
  11.121  void
  11.122 @@ -506,13 +513,12 @@
  11.123  				    const char *path);
  11.124  void razor_relocations_destroy(struct razor_relocations *relocations);
  11.125  
  11.126 -struct razor_rpm *razor_rpm_open(const char *filename,
  11.127 -				 struct razor_error **error);
  11.128 +struct razor_rpm *razor_rpm_open(const char *uri, struct razor_error **error);
  11.129  void razor_rpm_get_details(struct razor_rpm *rpm, ...);
  11.130  void razor_rpm_set_relocations(struct razor_rpm *rpm,
  11.131  			       struct razor_relocations *relocations);
  11.132  int razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
  11.133 -		      const char *root, int install_count,
  11.134 +		      const char *root_uri, int install_count,
  11.135  		      enum razor_stage_type stage);
  11.136  int razor_rpm_close(struct razor_rpm *rpm);
  11.137  
  11.138 @@ -599,13 +605,13 @@
  11.139   **/
  11.140  struct razor_root;
  11.141  
  11.142 -const char *razor_get_database_path();
  11.143 -void razor_set_database_path(const char *database_path);
  11.144 -int razor_root_create(const char *root, struct razor_error **error);
  11.145 +const char *razor_get_database_uri(void);
  11.146 +void razor_set_database_uri(const char *database_uri);
  11.147 +int razor_root_create(const char *root_uri, struct razor_error **error);
  11.148  struct razor_root *
  11.149 -razor_root_open(const char *root, struct razor_error **error);
  11.150 +razor_root_open(const char *root_uri, struct razor_error **error);
  11.151  struct razor_set *
  11.152 -razor_root_open_read_only(const char *root, struct razor_error **error);
  11.153 +razor_root_open_read_only(const char *root_uri, struct razor_error **error);
  11.154  struct razor_set *razor_root_get_system_set(struct razor_root *root);
  11.155  int razor_root_close(struct razor_root *root);
  11.156  int
  11.157 @@ -613,6 +619,41 @@
  11.158  		  struct razor_atomic *atomic);
  11.159  
  11.160  /**
  11.161 + * SECTION:uri-io
  11.162 + * @title: URI Input/Output
  11.163 + * @short_description: Functions to support non-file URI handlers
  11.164 + *
  11.165 + * Libraries that want to support URIs other than file URIs (which razor
  11.166 + * handles internally), can install their own URI handlers. Unsupported
  11.167 + * virtual functions should be set to %NULL. A fallback URI handler (which
  11.168 + * will be used if no scheme-specific handler is found) can be installed
  11.169 + * by passing scheme as %NULL. Finally, URI handlers can be removed by
  11.170 + * passing vtable as %NULL.
  11.171 + **/
  11.172 +
  11.173 +struct razor_uri_vtable {
  11.174 +	unsigned structure_size;
  11.175 +	int (*mkdir)(const char *path, mode_t mode, struct razor_error **error);
  11.176 +	int (*unlink)(const char *path, struct razor_error **error);
  11.177 +	int (*open)(const char *path, int flags, mode_t mode,
  11.178 +		    struct razor_error **error);
  11.179 +	int (*move)(const char *path, const char *dest,
  11.180 +		    struct razor_error **error);
  11.181 +	void *(*get_contents)(const char *path, size_t *length, int _private,
  11.182 +			      struct razor_error **error);
  11.183 +	int (*free_contents)(void *addr, size_t length);
  11.184 +	int (*is_directory)(const char *path, struct razor_error **error);
  11.185 +	char *(*mkdtemp_near)(const char *path, const char *_template,
  11.186 +			      struct razor_error **error);
  11.187 +	void *(*opendir)(const char *path, struct razor_error **error);
  11.188 +	char *(*readdir)(void *dir, struct razor_error **error);
  11.189 +	int (*closedir)(void *dir, struct razor_error **error);
  11.190 +};
  11.191 +
  11.192 +int razor_uri_set_vtable(const char *scheme, struct razor_uri_vtable *vtable,
  11.193 +			 struct razor_error **error);
  11.194 +
  11.195 +/**
  11.196   * SECTION:misc
  11.197   * @title: Miscellaneous Functions
  11.198   * @short_description: Various helper functions
  11.199 @@ -636,12 +677,15 @@
  11.200  
  11.201  char *razor_concat(const char *s, ...) RAZOR_MALLOC RAZOR_NULL_TERMINATED;
  11.202  
  11.203 -char *razor_path_add_root(const char *path, const char *root) RAZOR_MALLOC;
  11.204 -char *razor_path_from_url(const char *url) RAZOR_MALLOC;
  11.205 +char *razor_path_from_uri(const char *uri, struct razor_error **error)
  11.206 +      RAZOR_MALLOC;
  11.207 +char *razor_path_to_uri(const char *path) RAZOR_MALLOC;
  11.208 +char *razor_path_relative_to_uri(const char *file_uri, const char *path,
  11.209 +				 struct razor_error **error) RAZOR_MALLOC;
  11.210  
  11.211  const char *razor_system_arch(void);
  11.212  
  11.213 -int razor_dump_database(FILE *fp, const char *root, const char *filename,
  11.214 +int razor_dump_database(FILE *fp, const char *root_uri, const char *filename,
  11.215  			struct razor_error **error);
  11.216  
  11.217  #endif /* _RAZOR_H_ */
    12.1 --- a/librazor/root.c	Sat Jun 11 17:56:48 2016 +0100
    12.2 +++ b/librazor/root.c	Mon Jul 04 10:48:18 2016 +0100
    12.3 @@ -1,7 +1,7 @@
    12.4  /*
    12.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    12.6   * Copyright (C) 2008  Red Hat, Inc
    12.7 - * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
    12.8 + * Copyright (C) 2009, 2011, 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    12.9   *
   12.10   * This program is free software; you can redistribute it and/or modify
   12.11   * it under the terms of the GNU General Public License as published by
   12.12 @@ -25,7 +25,6 @@
   12.13  #include <stdio.h>
   12.14  #include <string.h>
   12.15  #include <errno.h>
   12.16 -#include <sys/stat.h>
   12.17  #include <dirent.h>
   12.18  #include <unistd.h>
   12.19  #include <fcntl.h>
   12.20 @@ -59,102 +58,130 @@
   12.21   */
   12.22  static const char system_lock_filename[] = "system-next.rzdb";
   12.23  #ifdef MSWIN_API
   12.24 -#define RAZOR_DATABASE_PATH	NULL
   12.25 +#define RAZOR_DATABASE_URI	NULL
   12.26  #else
   12.27 -#define RAZOR_DATABASE_PATH	"/var/lib/razor"
   12.28 +/*
   12.29 + * The non-MSWIN default is a relative-ref and thus affected by the root
   12.30 + */
   12.31 +#define RAZOR_DATABASE_URI	"var/lib/razor"
   12.32  #endif
   12.33 -static char *razor_database_path = RAZOR_DATABASE_PATH;
   12.34 -static int razor_database_path_alloced = FALSE;
   12.35 +static char *razor_database_uri = RAZOR_DATABASE_URI;
   12.36 +static int razor_database_uri_alloced = FALSE;
   12.37  
   12.38  struct razor_root {
   12.39  	struct razor_set *system;
   12.40 -	char *path;
   12.41 +	char *uri;
   12.42  };
   12.43  
   12.44  static void
   12.45  razor_root_init(void)
   12.46  {
   12.47  #ifdef MSWIN_API
   12.48 -	static char database_path[MAX_PATH];
   12.49 -	if (!razor_database_path) {
   12.50 +	/*
   12.51 +	 * The MSWIN default is an absolute-URI and thus unaffected by the root
   12.52 +	 */
   12.53 +	char database_path[MAX_PATH];
   12.54 +	if (!razor_database_uri) {
   12.55  		SHGetFolderPath(NULL,
   12.56  			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
   12.57  			database_path);
   12.58  		strcat(database_path, "\\Razor");
   12.59 -		razor_database_path = database_path;
   12.60 -		razor_database_path_alloced = FALSE;
   12.61 +		razor_database_uri = razor_path_to_uri(database_path);
   12.62 +		razor_database_uri_alloced = TRUE;
   12.63  	}
   12.64  #endif
   12.65  }
   12.66  
   12.67 -RAZOR_EXPORT const char *
   12.68 -razor_get_database_path()
   12.69 +RAZOR_EXPORT const char *razor_get_database_uri(void)
   12.70  {
   12.71  	razor_root_init();
   12.72 -
   12.73 -	return razor_database_path;
   12.74 +	return razor_database_uri;
   12.75  }
   12.76  
   12.77  RAZOR_EXPORT void
   12.78 -razor_set_database_path(const char *database_path)
   12.79 +razor_set_database_uri(const char *database_uri)
   12.80  {
   12.81 -	if (razor_database_path_alloced)
   12.82 -		free(razor_database_path);
   12.83 +	if (razor_database_uri_alloced)
   12.84 +		free(razor_database_uri);
   12.85  
   12.86 -	if (database_path) {
   12.87 -		razor_database_path = strdup(database_path);
   12.88 -		razor_database_path_alloced = TRUE;
   12.89 +	if (database_uri) {
   12.90 +		razor_database_uri = strdup(database_uri);
   12.91 +		razor_database_uri_alloced = TRUE;
   12.92  	} else {
   12.93 -		razor_database_path = RAZOR_DATABASE_PATH;
   12.94 -		razor_database_path_alloced = FALSE;
   12.95 +		razor_database_uri = RAZOR_DATABASE_URI;
   12.96 +		razor_database_uri_alloced = FALSE;
   12.97  	}
   12.98  }
   12.99  
  12.100 +char *razor_resolve_database_file(const char *root_uri, const char *filename,
  12.101 +				  struct razor_error **error)
  12.102 +{
  12.103 +	char *s, *uri;
  12.104 +
  12.105 +	razor_root_init();
  12.106 +
  12.107 +	s = razor_concat(razor_database_uri, "/", filename, NULL);
  12.108 +
  12.109 +	uri = razor_resolve_uri_root(root_uri, s, -1, error);
  12.110 +
  12.111 +	free(s);
  12.112 +
  12.113 +	return uri;
  12.114 +}
  12.115 +
  12.116  RAZOR_EXPORT int
  12.117 -razor_root_create(const char *root, struct razor_error **error)
  12.118 +razor_root_create(const char *root_uri, struct razor_error **error)
  12.119  {
  12.120 -	int retval;
  12.121 -	struct stat buf;
  12.122 +	int retval, is_within_root, is_directory;
  12.123  	struct razor_set *set;
  12.124  	struct razor_atomic *atomic;
  12.125 -	char *file, *path;
  12.126 +	struct razor_error *tmp_err = NULL;
  12.127 +	char *uri;
  12.128  
  12.129 -	assert (root != NULL);
  12.130 +	uri = razor_resolve_database_file(root_uri, system_repo_filename,
  12.131 +					  error);
  12.132  
  12.133 -	razor_root_init();
  12.134 -	if (root[0] == '\0') {
  12.135 -		/* root is file system root */
  12.136 -	} else if (stat(root, &buf) < 0) {
  12.137 -		if (mkdir(root, 0777) < 0) {
  12.138 -			razor_set_error(error, RAZOR_POSIX_ERROR, errno, root,
  12.139 +	if (!uri)
  12.140 +		return -1;
  12.141 +
  12.142 +	if (razor_uri_is_directory(uri, NULL) >= 0) {
  12.143 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  12.144 +				RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL,
  12.145 +				"A razor install root is already initialized");
  12.146 +		free(uri);
  12.147 +		return -1;
  12.148 +	}
  12.149 +
  12.150 +	is_within_root = root_uri && strchr(root_uri, '/') &&
  12.151 +			 str_has_prefix(uri, root_uri);
  12.152 +
  12.153 +	atomic = razor_atomic_open("Create initial package set");
  12.154 +
  12.155 +	if (is_within_root) {
  12.156 +		is_directory = razor_uri_is_directory(root_uri, NULL);
  12.157 +
  12.158 +		if (!is_directory) {
  12.159 +			razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR,
  12.160 +					root_uri, "Not a directory");
  12.161 +			return -1;
  12.162 +		} else if (is_directory < 0 &&
  12.163 +			   razor_uri_mkdir(root_uri, 0777, &tmp_err) < 0) {
  12.164 +			razor_set_error(error,
  12.165 +					razor_error_get_domain(tmp_err),
  12.166 +					razor_error_get_code(tmp_err),
  12.167 +					root_uri,
  12.168  					"Could not create install root");
  12.169  			return -1;
  12.170  		}
  12.171 -	} else if (!S_ISDIR(buf.st_mode)) {
  12.172 -		razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, root,
  12.173 -				"Not a directory");
  12.174 -		return -1;
  12.175 -	}
  12.176  
  12.177 -	file = razor_concat(razor_database_path, "/", system_repo_filename,
  12.178 -			    NULL);
  12.179 -	path = razor_path_add_root(file, root);
  12.180 -	retval = !stat(path, &buf);
  12.181 -	if (retval) {
  12.182 -		razor_set_error(error, RAZOR_GENERAL_ERROR,
  12.183 -				RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL,
  12.184 -				"A razor install root is already initialized");
  12.185 -		free(path);
  12.186 -		free(file);
  12.187 -		return retval;
  12.188 -	}
  12.189 +		razor_atomic_make_dirs(atomic, root_uri,
  12.190 +				       uri + strlen(root_uri));
  12.191 +	} else
  12.192 +		razor_atomic_make_dirs(atomic, "", uri);
  12.193  
  12.194 -	atomic = razor_atomic_open("Create initial package set");
  12.195 -	razor_atomic_make_dirs(atomic, root, file);
  12.196  	set = razor_set_create();
  12.197 -	razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
  12.198 -	free(path);
  12.199 -	free(file);
  12.200 +	razor_set_write(set, atomic, uri, RAZOR_SECTION_ALL);
  12.201 +	free(uri);
  12.202  	retval = razor_atomic_commit(atomic);
  12.203  	if (retval)
  12.204  		razor_propagate_error(error,
  12.205 @@ -167,17 +194,21 @@
  12.206  }
  12.207  
  12.208  RAZOR_EXPORT struct razor_root *
  12.209 -razor_root_open(const char *root, struct razor_error **error)
  12.210 +razor_root_open(const char *root_uri, struct razor_error **error)
  12.211  {
  12.212  	struct razor_root *image;
  12.213 -	char *s, *lock_path;
  12.214 +	char *lock_uri;
  12.215  	int r;
  12.216  
  12.217 -	assert (root != NULL);
  12.218 +	lock_uri = razor_resolve_database_file(root_uri, system_lock_filename,
  12.219 +					       error);
  12.220  
  12.221 -	razor_root_init();
  12.222 +	if (!lock_uri)
  12.223 +		return NULL;
  12.224 +
  12.225  	image = malloc(sizeof *image);
  12.226  	if (image == NULL) {
  12.227 +		free(lock_uri);
  12.228  		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
  12.229  				"Not enough memory");
  12.230  		return NULL;
  12.231 @@ -186,35 +217,37 @@
  12.232  	image->system = razor_set_create_without_root();
  12.233  	if (image->system == NULL) {
  12.234  		free(image);
  12.235 +		free(lock_uri);
  12.236  		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
  12.237  				"Not enough memory");
  12.238  		return NULL;
  12.239  	}
  12.240  
  12.241 -	s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
  12.242 -	lock_path = razor_path_add_root(s, root);
  12.243 -	free(s);
  12.244 +	r = razor_set_acquire_lock(image->system, lock_uri, 1);
  12.245  
  12.246 -	r = razor_set_aquire_lock(image->system, lock_path, 1);
  12.247 -
  12.248 -	free(lock_path);
  12.249 +	free(lock_uri);
  12.250  
  12.251  	if (r < 0) {
  12.252  		razor_set_error(error, RAZOR_GENERAL_ERROR,
  12.253  				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
  12.254 -				"Failed to aquire exclusive system lock");
  12.255 +				"Failed to acquire exclusive system lock");
  12.256  		razor_set_unref(image->system);
  12.257  		free(image);
  12.258  		return NULL;
  12.259  	}
  12.260  
  12.261 -	s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
  12.262 -	image->path = razor_path_add_root(s, root);
  12.263 -	free(s);
  12.264 +	image->uri = razor_resolve_database_file(root_uri, system_repo_filename,
  12.265 +						 error);
  12.266  
  12.267 -	if (razor_set_bind_sections(image->system, image->path,
  12.268 +	if (!image->uri) {
  12.269 +		razor_set_unref(image->system);
  12.270 +		free(image);
  12.271 +		return NULL;
  12.272 +	}
  12.273 +
  12.274 +	if (razor_set_bind_sections(image->system, image->uri,
  12.275  				    RAZOR_SET_PRIVATE, error)) {
  12.276 -		free(image->path);
  12.277 +		free(image->uri);
  12.278  		razor_set_unref(image->system);
  12.279  		free(image);
  12.280  		return NULL;
  12.281 @@ -224,46 +257,47 @@
  12.282  }
  12.283  
  12.284  RAZOR_EXPORT struct razor_set *
  12.285 -razor_root_open_read_only(const char *root, struct razor_error **error)
  12.286 +razor_root_open_read_only(const char *root_uri, struct razor_error **error)
  12.287  {
  12.288 -	char *s, *path;
  12.289 +	int r;
  12.290 +	char *uri;
  12.291  	struct razor_set *set;
  12.292  
  12.293 -	assert (root != NULL);
  12.294 +	uri = razor_resolve_database_file(root_uri, system_lock_filename,
  12.295 +					  error);
  12.296  
  12.297 -	razor_root_init();
  12.298 +	if (!uri)
  12.299 +		return NULL;
  12.300 +
  12.301  	set = razor_set_create_without_root();
  12.302  	if (set == NULL) {
  12.303 +		free(uri);
  12.304  		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
  12.305  				"Not enough memory");
  12.306  		return NULL;
  12.307  	}
  12.308  
  12.309 -	s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
  12.310 -	path = razor_path_add_root(s, root);
  12.311 -	free(s);
  12.312 +	r = razor_set_acquire_lock(set, uri, 0);
  12.313  
  12.314 -	if (razor_set_aquire_lock(set, path, 0) < 0) {
  12.315 +	free(uri);
  12.316 +
  12.317 +	if (r < 0) {
  12.318  		razor_set_error(error, RAZOR_GENERAL_ERROR,
  12.319  				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
  12.320 -				"Failed to aquire non-exclusive system lock");
  12.321 -		free(path);
  12.322 +				"Failed to acquire non-exclusive system lock");
  12.323  		razor_set_unref(set);
  12.324  		return NULL;
  12.325  	}
  12.326  
  12.327 -	free(path);
  12.328 +	uri = razor_resolve_database_file(root_uri, system_repo_filename,
  12.329 +					  error);
  12.330  
  12.331 -	s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
  12.332 -	path = razor_path_add_root(s, root);
  12.333 -	free(s);
  12.334 -
  12.335 -	if (razor_set_bind_sections(set, path, 0, error)) {
  12.336 +	if (!uri || razor_set_bind_sections(set, uri, 0, error)) {
  12.337  		razor_set_unref(set);
  12.338  		set = NULL;
  12.339  	}
  12.340  
  12.341 -	free(path);
  12.342 +	free(uri);
  12.343  
  12.344  	return set;
  12.345  }
  12.346 @@ -282,7 +316,7 @@
  12.347  	assert (root != NULL);
  12.348  
  12.349  	razor_set_unref(root->system);
  12.350 -	free(root->path);
  12.351 +	free(root->uri);
  12.352  	free(root);
  12.353  
  12.354  	return 0;
  12.355 @@ -297,7 +331,7 @@
  12.356  	assert (root != NULL);
  12.357  	assert (next != NULL);
  12.358  
  12.359 -	handle = razor_atomic_create_file(atomic, root->path,
  12.360 +	handle = razor_atomic_create_file(atomic, root->uri,
  12.361  					  S_IRWXU | S_IRWXG | S_IRWXO);
  12.362  	if (handle < 0)
  12.363  		return handle;
    13.1 --- a/librazor/rpm.c	Sat Jun 11 17:56:48 2016 +0100
    13.2 +++ b/librazor/rpm.c	Mon Jul 04 10:48:18 2016 +0100
    13.3 @@ -1,7 +1,7 @@
    13.4  /*
    13.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    13.6   * Copyright (C) 2008  Red Hat, Inc
    13.7 - * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
    13.8 + * Copyright (C) 2009, 2011, 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    13.9   *
   13.10   * This program is free software; you can redistribute it and/or modify
   13.11   * it under the terms of the GNU General Public License as published by
   13.12 @@ -25,13 +25,10 @@
   13.13  #include <stdlib.h>
   13.14  #include <string.h>
   13.15  #include <errno.h>
   13.16 -#include <sys/stat.h>
   13.17 -#include <sys/types.h>
   13.18  #if HAVE_SYS_WAIT_H
   13.19  #include <sys/wait.h>
   13.20  #endif
   13.21  #include <fcntl.h>
   13.22 -#include <dirent.h>
   13.23  #include <unistd.h>
   13.24  #if MSWIN_API
   13.25  #include <winsock2.h>	/* For ntohl() */
   13.26 @@ -620,7 +617,7 @@
   13.27  }
   13.28  
   13.29  RAZOR_EXPORT struct razor_rpm *
   13.30 -razor_rpm_open(const char *filename, struct razor_error **error)
   13.31 +razor_rpm_open(const char *uri, struct razor_error **error)
   13.32  {
   13.33  	struct rpm_lead *lead;
   13.34  	struct razor_rpm *rpm;
   13.35 @@ -628,7 +625,7 @@
   13.36  	unsigned int count, i, nindex, hsize;
   13.37  	const char *name, *prefix;
   13.38  
   13.39 -	assert (filename != NULL);
   13.40 +	assert (uri != NULL);
   13.41  
   13.42  	rpm = zalloc(sizeof *rpm);
   13.43  	if (rpm == NULL) {
   13.44 @@ -638,7 +635,7 @@
   13.45  	}
   13.46  	memset(rpm, 0, sizeof *rpm);
   13.47  
   13.48 -	rpm->map = razor_file_get_contents(filename, &rpm->size, 0, error);
   13.49 +	rpm->map = razor_uri_get_contents(uri, &rpm->size, 0, error);
   13.50  	if (!rpm->map) {
   13.51  		free(rpm);
   13.52  		return NULL;
   13.53 @@ -646,11 +643,11 @@
   13.54  
   13.55  	lead = rpm->map;
   13.56  	if (rpm->size < RPM_LEAD_SIZE ||
   13.57 -	    strncmp(lead->magic,RPM_LEAD_MAGIC,4) || lead->major != 3) {
   13.58 +	    strncmp((char *)lead->magic,RPM_LEAD_MAGIC,4) || lead->major != 3) {
   13.59  		razor_rpm_close(rpm);
   13.60  		razor_set_error(error, RAZOR_GENERAL_ERROR,
   13.61  				RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
   13.62 -				filename, "Not a recognized RPM format file");
   13.63 +				uri, "Not a recognized RPM format file");
   13.64  		return NULL;
   13.65  	}
   13.66  
   13.67 @@ -682,8 +679,7 @@
   13.68  			razor_rpm_close(rpm);
   13.69  			razor_set_error(error, RAZOR_GENERAL_ERROR,
   13.70  					RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
   13.71 -					filename,
   13.72 -					"Old filenames not supported");
   13.73 +					uri, "Old filenames not supported");
   13.74  			return NULL;
   13.75  		}
   13.76  	}
   13.77 @@ -704,8 +700,7 @@
   13.78  			razor_rpm_close(rpm);
   13.79  			razor_set_error(error, RAZOR_GENERAL_ERROR,
   13.80  					RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
   13.81 -					filename,
   13.82 -					"Default prefix not supported");
   13.83 +					uri, "Default prefix not supported");
   13.84  			return NULL;
   13.85  		}
   13.86  	}
   13.87 @@ -748,7 +743,7 @@
   13.88  #define RESERVED     0xE0 /* bits 5..7: reserved */
   13.89  
   13.90  struct installer {
   13.91 -	const char *root;
   13.92 +	const char *root_uri;
   13.93  	struct razor_rpm *rpm;
   13.94  	struct razor_atomic *atomic;
   13.95  	z_stream stream;
   13.96 @@ -808,13 +803,47 @@
   13.97  static int
   13.98  create_path(struct installer *installer, const char *path, unsigned int mode)
   13.99  {
  13.100 -	char *s, *buffer;
  13.101 -	int h, ret;
  13.102 +	const char *s, *relative;
  13.103 +	char *uri, *buffer;
  13.104 +	int h, ret, is_within_root;
  13.105 +	struct razor_error *tmp_error = NULL;
  13.106  
  13.107 -	if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
  13.108 +	uri = razor_path_to_uri(path);
  13.109 +
  13.110 +	if (str_has_prefix(uri, "file:///"))
  13.111 +		relative = uri + 8;
  13.112 +	else if (str_has_prefix(uri, "file:/"))
  13.113 +		relative = uri + 6;
  13.114 +	else if (str_has_prefix(uri, "file:"))
  13.115 +		relative = uri + 5;
  13.116 +	else if (str_has_prefix(uri, "/"))
  13.117 +		relative = uri + 1;
  13.118 +	else
  13.119 +		relative = uri;
  13.120 +
  13.121 +	buffer = razor_resolve_uri_root(installer->root_uri, relative, 1,
  13.122 +					&tmp_error);
  13.123 +
  13.124 +	if (!buffer) {
  13.125 +		razor_atomic_propagate_error(installer->atomic, tmp_error,
  13.126 +					     NULL);
  13.127 +		free(uri);
  13.128  		return -1;
  13.129 +	}
  13.130  
  13.131 -	buffer = razor_concat(installer->root, path, NULL);
  13.132 +	is_within_root = installer->root_uri &&
  13.133 +			 str_has_prefix(buffer, installer->root_uri);
  13.134 +
  13.135 +	if (is_within_root)
  13.136 +		ret = razor_atomic_make_dirs(installer->atomic,
  13.137 +					     installer->root_uri, relative);
  13.138 +	else
  13.139 +		ret = razor_atomic_make_dirs(installer->atomic, "", buffer);
  13.140 +
  13.141 +	free(uri);
  13.142 +
  13.143 +	if (ret)
  13.144 +		return ret;
  13.145  
  13.146  	switch (mode >> 12) {
  13.147  	case REG:
  13.148 @@ -831,7 +860,8 @@
  13.149  					       installer->length))
  13.150  				return -1;
  13.151  		}
  13.152 -		return razor_atomic_close(installer->atomic, h);
  13.153 +		ret = razor_atomic_close(installer->atomic, h);
  13.154 +		break;
  13.155  	case XDIR:
  13.156  		ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
  13.157  		free(buffer);
  13.158 @@ -842,16 +872,17 @@
  13.159  			return -1;
  13.160  		if (installer->length >= sizeof installer->buffer) {
  13.161  			razor_atomic_abort(installer->atomic,
  13.162 -			  RAZOR_GENERAL_ERROR,
  13.163 -			  RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
  13.164 -			  "Link target too long");
  13.165 +					   RAZOR_GENERAL_ERROR,
  13.166 +					   RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
  13.167 +					   "Link target too long");
  13.168  			return -1;
  13.169  		}
  13.170  		installer->buffer[installer->length] = '\0';
  13.171  		ret = razor_atomic_create_symlink(installer->atomic,
  13.172 -		  (const char *)installer->buffer, buffer);
  13.173 +						  (const char *)installer->buffer,
  13.174 +						  buffer);
  13.175  		free(buffer);
  13.176 -		return ret;
  13.177 +		break;
  13.178  #else
  13.179  		s = "Symbolic links";
  13.180  		goto unsupported;
  13.181 @@ -861,9 +892,9 @@
  13.182  unsupported:
  13.183  		free(buffer);
  13.184  		buffer = razor_concat(s, " are not supported on this platform",
  13.185 -		  NULL);
  13.186 +				      NULL);
  13.187  		razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR,
  13.188 -		  RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, buffer);
  13.189 +				   RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, buffer);
  13.190  		free(buffer);
  13.191  		return -1;
  13.192  	case CDEV:
  13.193 @@ -878,9 +909,12 @@
  13.194  	default:
  13.195  		free(buffer);
  13.196  		razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR,
  13.197 -		  RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, "Unknown file type");
  13.198 +				   RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
  13.199 +				   "Unknown file type");
  13.200  		return -1;
  13.201  	}
  13.202 +
  13.203 +	return ret;
  13.204  }
  13.205  
  13.206  static int chroot_push(const char *root)
  13.207 @@ -912,12 +946,14 @@
  13.208  }
  13.209  
  13.210  static int
  13.211 -run_script_lua(const char *root, unsigned int script_tag, const char *script,
  13.212 -	       int arg1)
  13.213 +run_script_lua(const char *root_uri, unsigned int script_tag,
  13.214 +	       const char *script, int arg1, struct razor_error **error)
  13.215  {
  13.216  	int root_fd, retval;
  13.217 +	const char *name;
  13.218  #if HAVE_LUA
  13.219 -	const char *name;
  13.220 +	char *root;
  13.221 +#endif
  13.222  
  13.223  	switch(script_tag) {
  13.224  		case RPMTAG_PREIN:
  13.225 @@ -936,12 +972,19 @@
  13.226  			name = "script";
  13.227  			break;
  13.228  	}
  13.229 -	root_fd = chroot_push(root);
  13.230 +
  13.231 +#if HAVE_LUA
  13.232 +	root = razor_path_from_uri(root_uri, error);
  13.233 +	if (!root)
  13.234 +		return -1;
  13.235 +	root_fd = root ? chroot_push(root) : -1;
  13.236  	retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1,
  13.237  				arg1);
  13.238 +	free(root);
  13.239  	chroot_pop(root_fd);
  13.240  #else	/* HAVE_LUA */
  13.241 -	fprintf(stderr, "lua not available to run script\n");
  13.242 +	razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_FAILED,
  13.243 +			name, "lua not available to run script");
  13.244  	retval = -1;
  13.245  #endif	/* HAVE_LUA */
  13.246  
  13.247 @@ -949,12 +992,12 @@
  13.248  }
  13.249  
  13.250  static int
  13.251 -run_script_external(const char *root, const char *program, const char *script,
  13.252 -		    int arg1)
  13.253 +run_script_external(const char *root_uri, const char *program,
  13.254 +		    const char *script, int arg1, struct razor_error **error)
  13.255  {
  13.256  	int root_fd, retval;
  13.257  	FILE *fp;
  13.258 -	char buf[32], *command;
  13.259 +	char buf[32], *command, *root;
  13.260  
  13.261  	if (program == NULL) {
  13.262  #if MSWIN_API
  13.263 @@ -971,7 +1014,11 @@
  13.264  #endif
  13.265  	}
  13.266  
  13.267 +	root = razor_path_from_uri(root_uri, error);
  13.268 +	if (!root)
  13.269 +		return -1;
  13.270  	root_fd = chroot_push(root);
  13.271 +	free(root);
  13.272  	if (arg1 >= 0) {
  13.273  		sprintf(buf, "%d", arg1);
  13.274  		command = malloc(strlen(program) + strlen(buf) + 2);
  13.275 @@ -982,10 +1029,11 @@
  13.276  	free(command);
  13.277  
  13.278  	if (!fp) {
  13.279 -		perror(program);
  13.280 +		razor_set_error_posix(error, program);
  13.281  		retval = -1;
  13.282  	} else if (script && fwrite(script, strlen(script), 1, fp) != 1) {
  13.283 -		perror("failed to write script to program");
  13.284 +		razor_set_error_posix(error,
  13.285 +				      "failed to write script to program");
  13.286  		retval = -1;
  13.287  	} else
  13.288  		retval = 0;
  13.289 @@ -998,8 +1046,8 @@
  13.290  }
  13.291  
  13.292  static int
  13.293 -run_script(struct installer *installer,
  13.294 -	   unsigned int program_tag, unsigned int script_tag, int arg1)
  13.295 +run_script(struct installer *installer, unsigned int program_tag,
  13.296 +	   unsigned int script_tag, int arg1, struct razor_error **error)
  13.297  {
  13.298  	int i, retval;
  13.299  	struct razor_rpm *rpm = installer->rpm;
  13.300 @@ -1024,11 +1072,11 @@
  13.301  	}
  13.302  
  13.303  	if (program && strcmp(program, "<lua>") == 0)
  13.304 -		retval = run_script_lua(installer->root, script_tag, script,
  13.305 -					arg1);
  13.306 +		retval = run_script_lua(installer->root_uri, script_tag,
  13.307 +					script, arg1, error);
  13.308  	else
  13.309 -		retval = run_script_external(installer->root, program, script,
  13.310 -					     arg1);
  13.311 +		retval = run_script_external(installer->root_uri, program,
  13.312 +					     script, arg1, error);
  13.313  
  13.314  	if (rpm->relocations) {
  13.315  		environment_unset(&env);
  13.316 @@ -1040,7 +1088,8 @@
  13.317  
  13.318  int
  13.319  razor_run_script(const char *root, enum razor_property_flags script,
  13.320 -		 const char *program, const char *body, int arg1)
  13.321 +		 const char *program, const char *body, int arg1,
  13.322 +		 struct razor_error **error)
  13.323  {
  13.324  	int retval;
  13.325  	unsigned int script_tag;
  13.326 @@ -1071,10 +1120,10 @@
  13.327  			script_tag = 0;
  13.328  			break;
  13.329  		}
  13.330 -		retval = run_script_lua(root, script_tag, body, arg1);
  13.331 +		retval = run_script_lua(root, script_tag, body, arg1, error);
  13.332  	}
  13.333  	else
  13.334 -		retval = run_script_external(root, program, body, arg1);
  13.335 +		retval = run_script_external(root, program, body, arg1, error);
  13.336  
  13.337  	return retval;
  13.338  }
  13.339 @@ -1164,30 +1213,38 @@
  13.340  
  13.341  RAZOR_EXPORT int
  13.342  razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
  13.343 -		  const char *root, int install_count,
  13.344 +		  const char *root_uri, int install_count,
  13.345  		  enum razor_stage_type stage)
  13.346  {
  13.347  	struct installer installer;
  13.348  	struct cpio_file_header *header;
  13.349 -	struct stat buf;
  13.350  	unsigned int mode;
  13.351  	const char *path;
  13.352  	size_t filesize;
  13.353  	char *s;
  13.354 -	int retval = 0, code;
  13.355 +	int retval = 0, domain, code;
  13.356 +	struct razor_error *tmp_error = NULL;
  13.357  
  13.358  	assert (rpm != NULL);
  13.359 -	assert (root != NULL);
  13.360 +	assert (root_uri != NULL);
  13.361  
  13.362  	installer.rpm = rpm;
  13.363 -	installer.root = root;
  13.364 +	installer.root_uri = root_uri;
  13.365  	installer.atomic = atomic;
  13.366  
  13.367  	/* FIXME: Only do this before a transaction, not per rpm. */
  13.368 -	if (*root && ((retval = stat(root, &buf)) || !S_ISDIR(buf.st_mode))) {
  13.369 -		code = retval ? errno : ENOTDIR;
  13.370 -		s = razor_concat(root, ": Directory does not exist", NULL);
  13.371 -		razor_atomic_abort(atomic, RAZOR_POSIX_ERROR, code, s);
  13.372 +	if (*root_uri && razor_uri_is_directory(root_uri, &tmp_error) <= 0) {
  13.373 +		if (tmp_error) {
  13.374 +			domain = razor_error_get_domain(tmp_error);
  13.375 +			code = razor_error_get_code(tmp_error);
  13.376 +			razor_error_free(tmp_error);
  13.377 +			tmp_error = NULL;
  13.378 +		} else {
  13.379 +			domain = RAZOR_POSIX_ERROR;
  13.380 +			code = ENOTDIR;
  13.381 +		}
  13.382 +		s = razor_concat(root_uri, ": Directory does not exist", NULL);
  13.383 +		razor_atomic_abort(atomic, domain, code, s);
  13.384  		free(s);
  13.385  		return -1;
  13.386  	}
  13.387 @@ -1195,9 +1252,14 @@
  13.388  	if (rpm->relocations)
  13.389  		razor_relocations_set_rpm(rpm->relocations, rpm);
  13.390  
  13.391 -	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  13.392 +	if (stage & RAZOR_STAGE_SCRIPTS_PRE) {
  13.393  		retval = run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
  13.394 -				    install_count);
  13.395 +				    install_count, &tmp_error);
  13.396 +		if (retval) {
  13.397 +			razor_atomic_propagate_error(atomic, tmp_error, NULL);
  13.398 +			tmp_error = NULL;
  13.399 +		}
  13.400 +	}
  13.401  
  13.402  	if (!retval && (stage & RAZOR_STAGE_FILES)) {
  13.403  		if (installer_init(&installer))
  13.404 @@ -1244,9 +1306,14 @@
  13.405  		retval = razor_atomic_in_error_state(atomic);
  13.406  	}
  13.407  
  13.408 -	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST))
  13.409 +	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) {
  13.410  		retval = run_script(&installer, RPMTAG_POSTINPROG,
  13.411 -				    RPMTAG_POSTIN, install_count);
  13.412 +				    RPMTAG_POSTIN, install_count, &tmp_error);
  13.413 +		if (retval) {
  13.414 +			razor_atomic_propagate_error(atomic, tmp_error, NULL);
  13.415 +			tmp_error = NULL;
  13.416 +		}
  13.417 +	}
  13.418  
  13.419  	return retval;
  13.420  }
  13.421 @@ -1260,7 +1327,7 @@
  13.422  
  13.423  	free(rpm->dirs);
  13.424  	free(rpm->prefixes);
  13.425 -	err = razor_file_free_contents(rpm->map, rpm->size);
  13.426 +	err = razor_uri_free_contents(rpm->map, rpm->size);
  13.427  	free(rpm->evr);
  13.428  	free(rpm);
  13.429  
    14.1 --- a/librazor/test-lua.c	Sat Jun 11 17:56:48 2016 +0100
    14.2 +++ b/librazor/test-lua.c	Mon Jul 04 10:48:18 2016 +0100
    14.3 @@ -1,5 +1,5 @@
    14.4  /*
    14.5 - * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
    14.6 + * Copyright (C) 2009, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    14.7   *
    14.8   * This program is free software; you can redistribute it and/or modify
    14.9   * it under the terms of the GNU General Public License as published by
   14.10 @@ -22,8 +22,6 @@
   14.11  #include <stdio.h>
   14.12  #include <string.h>
   14.13  #include <errno.h>
   14.14 -#include <sys/types.h>
   14.15 -#include <sys/stat.h>
   14.16  #include <dirent.h>
   14.17  #include <unistd.h>
   14.18  #include <math.h>
   14.19 @@ -63,18 +61,19 @@
   14.20  	int r;
   14.21  	void *script;
   14.22  	size_t len;
   14.23 -	char *s, *test_file, *srcdir;
   14.24 +	char *s, *test_uri, *srcdir, *suffix, *cwd;
   14.25  	FILE *fp;
   14.26  	struct razor_error *error = NULL;
   14.27 +	struct razor_uri base_ru, test_ru, ru;
   14.28  
   14.29  	if (argc > 2) {
   14.30 -		fprintf(stderr, "usage: %s [TESTS-FILE]\n", argv[0]);
   14.31 +		fprintf(stderr, "usage: %s [TESTS-URI]\n", argv[0]);
   14.32  		exit(1);
   14.33  	}
   14.34  	if (argc == 2)
   14.35 -		test_file = argv[1];
   14.36 +		test_uri = argv[1];
   14.37  	else
   14.38 -		test_file = "test.lua";
   14.39 +		test_uri = "test.lua";
   14.40  
   14.41  	if (!mkdtemp(root)) {
   14.42  		perror(root);
   14.43 @@ -95,31 +94,68 @@
   14.44  	chmod(s, S_IRUSR | S_IWUSR | S_IXUSR);
   14.45  	free(s);
   14.46  
   14.47 -	script = razor_file_get_contents(test_file, &len, 0, &error);
   14.48 +	for (len = 32;; len *= 2) {
   14.49 +	    cwd = malloc(len);
   14.50 +	    if (getcwd(cwd, len))
   14.51 +		    break;
   14.52 +	    free(cwd);
   14.53 +	}
   14.54 +	cwd = realloc(cwd, strlen(cwd) + 1);
   14.55 +
   14.56 +	s = razor_concat("file:", cwd, NULL);
   14.57 +	if (razor_uri_parse(&test_ru, test_uri, &error) ||
   14.58 +	    razor_uri_parse(&base_ru, s, &error)) {
   14.59 +		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   14.60 +		razor_error_free(error);
   14.61 +		exit(1);
   14.62 +	}
   14.63 +	free(s);
   14.64 +
   14.65 +	razor_uri_resolve(&ru, &base_ru, &test_ru);
   14.66 +	razor_uri_destroy(&base_ru);
   14.67 +	s = razor_uri_recompose(&ru);
   14.68 +	razor_uri_destroy(&ru);
   14.69 +	script = razor_uri_get_contents(s, &len, 0, &error);
   14.70 +	free(s);
   14.71  	if (!script) {
   14.72  		srcdir = getenv("srcdir");
   14.73 -		if (srcdir && errno == ENOENT && *test_file != '/') {
   14.74 +		if (srcdir && errno == ENOENT) {
   14.75  			razor_error_free(error);
   14.76 -			s = malloc(strlen(srcdir) + strlen(test_file) + 2);
   14.77 -			strcpy(s, srcdir);
   14.78 -			strcat(s, "/");
   14.79 -			strcat(s, test_file);
   14.80 -			script = razor_file_get_contents(s, &len, 0, &error);
   14.81 -			if (!script) {
   14.82 +			error = NULL;
   14.83 +			suffix = srcdir[strlen(srcdir) - 1] == '/' ? NULL : "/";
   14.84 +			if (*srcdir == '/')
   14.85 +				s = razor_concat("file:", srcdir, suffix, NULL);
   14.86 +			else
   14.87 +				s = razor_concat("file:", cwd, "/", srcdir,
   14.88 +						 suffix, NULL);
   14.89 +			razor_uri_parse(&base_ru, s, &error);
   14.90 +			free(s);
   14.91 +			if (!error) {
   14.92 +				razor_uri_resolve(&ru, &base_ru, &test_ru);
   14.93 +				razor_uri_destroy(&base_ru);
   14.94 +				s = razor_uri_recompose(&ru);
   14.95 +				razor_uri_destroy(&ru);
   14.96 +				script = razor_uri_get_contents(s, &len, 0,
   14.97 +								&error);
   14.98 +				free(s);
   14.99 +			}
  14.100 +			if (error) {
  14.101  				fprintf(stderr, "%s\n",
  14.102  					razor_error_get_msg(error));
  14.103  				razor_error_free(error);
  14.104  				exit(1);
  14.105  			}
  14.106 -			free(s);
  14.107  		} else {
  14.108  			fprintf(stderr, "%s\n", razor_error_get_msg(error));
  14.109  			razor_error_free(error);
  14.110  			exit(1);
  14.111  		}
  14.112  	}
  14.113 -	r = run_lua_script(root, test_file, script, len, -1);
  14.114 -	razor_file_free_contents(script, len);
  14.115 +	razor_uri_destroy(&test_ru);
  14.116 +	free(cwd);
  14.117 +
  14.118 +	r = run_lua_script(root, test_uri, script, len, -1);
  14.119 +	razor_uri_free_contents(script, len);
  14.120  
  14.121  	recursive_remove(root);
  14.122  	exit(r ? 1 : 0);
    15.1 --- a/librazor/test-pfu.c	Sat Jun 11 17:56:48 2016 +0100
    15.2 +++ b/librazor/test-pfu.c	Mon Jul 04 10:48:18 2016 +0100
    15.3 @@ -1,5 +1,5 @@
    15.4  /*
    15.5 - * Copyright (C) 2014  J. Ali Harlow <ali@juiblex.co.uk>
    15.6 + * Copyright (C) 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    15.7   *
    15.8   * This program is free software; you can redistribute it and/or modify
    15.9   * it under the terms of the GNU General Public License as published by
   15.10 @@ -26,17 +26,18 @@
   15.11  #endif
   15.12  #include "razor.h"
   15.13  
   15.14 -int is_ascii_letter(char c)
   15.15 +#ifdef MSWIN_API
   15.16 +static int is_ascii_letter(char c)
   15.17  {
   15.18  	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
   15.19  }
   15.20  
   15.21 -int is_slash(char c)
   15.22 +static int is_slash(char c)
   15.23  {
   15.24  	return c == '/' || c == '\\';
   15.25  }
   15.26  
   15.27 -const char *mswin_path(const char *path)
   15.28 +static const char *mswin_path(const char *path)
   15.29  {
   15.30  	if (path == NULL)
   15.31  		return NULL;
   15.32 @@ -47,8 +48,9 @@
   15.33  
   15.34  	return path;
   15.35  }
   15.36 +#endif
   15.37  
   15.38 -int path_cmp(const char *p1, const char *p2)
   15.39 +static int path_cmp(const char *p1, const char *p2)
   15.40  {
   15.41  #ifdef MSWIN_API
   15.42  	while(*p1 && *p2) {
   15.43 @@ -65,12 +67,13 @@
   15.44  #endif
   15.45  }
   15.46  
   15.47 -int test_pfu(const char *url, const char *path)
   15.48 +static int test_pfu(const char *uri, const char *path)
   15.49  {
   15.50  	char *s;
   15.51  	int r;
   15.52 +	struct razor_error *error = NULL;
   15.53  
   15.54 -	s = razor_path_from_url(url);
   15.55 +	s = razor_path_from_uri(uri, &error);
   15.56  
   15.57  #ifdef MSWIN_API
   15.58  	path = mswin_path(path);
   15.59 @@ -82,18 +85,21 @@
   15.60  		r = (s != path);
   15.61  
   15.62  	if (r) {
   15.63 -		fprintf(stderr, "Fail: razor_path_from_url(\"%s\")", url);
   15.64 +		fprintf(stderr, "Fail: razor_path_from_uri(\"%s\")", uri);
   15.65  		if (s)
   15.66  			fprintf(stderr, " returns \"%s\", expected", s);
   15.67  		else
   15.68 -			fprintf(stderr, " returns NULL, expected");
   15.69 +			fprintf(stderr, " fails (%s), expected",
   15.70 +				razor_error_get_msg(error));
   15.71  		if (path)
   15.72  			fprintf(stderr, " \"%s\"\n", path);
   15.73  		else
   15.74 -			fprintf(stderr, " NULL\n");
   15.75 +			fprintf(stderr, " failure\n");
   15.76  	}
   15.77  
   15.78  	free(s);
   15.79 +	if (error)
   15.80 +		razor_error_free(error);
   15.81  
   15.82  	return r;
   15.83  }
   15.84 @@ -101,7 +107,7 @@
   15.85  #ifdef MSWIN_API
   15.86  UINT saved_cp;
   15.87  
   15.88 -void cleanup_on_exit(void)
   15.89 +static void cleanup_on_exit(void)
   15.90  {
   15.91      SetConsoleOutputCP(saved_cp);
   15.92  }
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/librazor/test-uri.c	Mon Jul 04 10:48:18 2016 +0100
    16.3 @@ -0,0 +1,244 @@
    16.4 +/*
    16.5 + * Copyright (C) 2016  J. Ali Harlow <ali@juiblex.co.uk>
    16.6 + *
    16.7 + * This program is free software; you can redistribute it and/or modify
    16.8 + * it under the terms of the GNU General Public License as published by
    16.9 + * the Free Software Foundation; either version 2 of the License, or
   16.10 + * (at your option) any later version.
   16.11 + *
   16.12 + * This program is distributed in the hope that it will be useful,
   16.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16.15 + * GNU General Public License for more details.
   16.16 + *
   16.17 + * You should have received a copy of the GNU General Public License along
   16.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
   16.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   16.20 + */
   16.21 +
   16.22 +#include "config.h"
   16.23 +
   16.24 +#include <stdlib.h>
   16.25 +#include <stdio.h>
   16.26 +#include <string.h>
   16.27 +#include "razor.h"
   16.28 +#include "razor-internal.h"
   16.29 +
   16.30 +static int test_parse(const char *uri)
   16.31 +{
   16.32 +	struct razor_uri ru;
   16.33 +	struct razor_error *error = NULL;
   16.34 +	int r;
   16.35 +
   16.36 +	r = razor_uri_parse(&ru, uri, &error);
   16.37 +	razor_uri_destroy(&ru);
   16.38 +
   16.39 +	if (r < 0) {
   16.40 +		fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n",
   16.41 +			uri, razor_error_get_msg(error));
   16.42 +		return -1;
   16.43 +	}
   16.44 +
   16.45 +	return r;
   16.46 +}
   16.47 +
   16.48 +static int test_normalize(const char *uri, const char *expected_normalized_uri)
   16.49 +{
   16.50 +	struct razor_uri ru;
   16.51 +	struct razor_error *error = NULL;
   16.52 +	int r;
   16.53 +	char *normalized_uri;
   16.54 +
   16.55 +	r = razor_uri_parse(&ru, uri, &error);
   16.56 +
   16.57 +	if (r < 0) {
   16.58 +		razor_uri_destroy(&ru);
   16.59 +		fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n",
   16.60 +			uri, razor_error_get_msg(error));
   16.61 +		return -1;
   16.62 +	}
   16.63 +
   16.64 +	razor_uri_normalize(&ru);
   16.65 +	normalized_uri = razor_uri_recompose(&ru);
   16.66 +	razor_uri_destroy(&ru);
   16.67 +
   16.68 +	if (strcmp(normalized_uri, expected_normalized_uri)) {
   16.69 +		fprintf(stderr, "Fail: normalization of \"%s\" produces "
   16.70 +			"\"%s\", expected \"%s\"\n", uri, normalized_uri,
   16.71 +			expected_normalized_uri);
   16.72 +		r = -1;
   16.73 +	}
   16.74 +
   16.75 +	free(normalized_uri);
   16.76 +	return r;
   16.77 +}
   16.78 +
   16.79 +static int test_resolve(const char *base_uri, const char *relative_reference,
   16.80 +  const char *expected_target_uri)
   16.81 +{
   16.82 +	struct razor_uri base_ru, rr_ru, target_ru;
   16.83 +	struct razor_error *error = NULL;
   16.84 +	char *target_uri;
   16.85 +	int r;
   16.86 +
   16.87 +	r = razor_uri_parse(&base_ru, base_uri, &error);
   16.88 +
   16.89 +	if (r < 0) {
   16.90 +		fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n",
   16.91 +			base_uri, razor_error_get_msg(error));
   16.92 +		return -1;
   16.93 +	}
   16.94 +
   16.95 +	r = razor_uri_parse(&rr_ru, relative_reference, &error);
   16.96 +
   16.97 +	if (r < 0) {
   16.98 +		fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n",
   16.99 +			relative_reference, razor_error_get_msg(error));
  16.100 +		razor_uri_destroy(&base_ru);
  16.101 +		return -1;
  16.102 +	}
  16.103 +
  16.104 +	razor_uri_resolve(&target_ru, &base_ru, &rr_ru);
  16.105 +	razor_uri_destroy(&base_ru);
  16.106 +	razor_uri_destroy(&rr_ru);
  16.107 +
  16.108 +	target_uri = razor_uri_recompose(&target_ru);
  16.109 +	razor_uri_destroy(&target_ru);
  16.110 +
  16.111 +	if (strcmp(target_uri, expected_target_uri)) {
  16.112 +		fprintf(stderr,
  16.113 +			"Fail: razor_uri_resolve(\"%s\", \"%s\") returns %s\n",
  16.114 +			base_uri, relative_reference, target_uri);
  16.115 +		free(target_uri);
  16.116 +		return -1;
  16.117 +	}
  16.118 +
  16.119 +	free(target_uri);
  16.120 +
  16.121 +	return 0;
  16.122 +}
  16.123 +
  16.124 +int main(int argc, char *argv[])
  16.125 +{
  16.126 +	int r = 0;
  16.127 +
  16.128 +	r |= test_parse("file:");
  16.129 +	r |= test_parse("file:/");
  16.130 +	r |= test_parse("file:///");
  16.131 +
  16.132 +	/* From RFC 3986 § 6.2.2 */
  16.133 +	r |= test_normalize("eXAMPLE://a/./b/../b/%63/%7bfoo%7d",
  16.134 +			    "example://a/b/c/%7Bfoo%7D");
  16.135 +
  16.136 +	/* From RFC 3986 § 5.4.1 */
  16.137 +	r |= test_resolve("http://a/b/c/d;p?q", "g:h", "g:h");
  16.138 +	r |= test_resolve("http://a/b/c/d;p?q", "g", "http://a/b/c/g");
  16.139 +	r |= test_resolve("http://a/b/c/d;p?q", "./g", "http://a/b/c/g");
  16.140 +	r |= test_resolve("http://a/b/c/d;p?q", "g/", "http://a/b/c/g/");
  16.141 +	r |= test_resolve("http://a/b/c/d;p?q", "/g", "http://a/g");
  16.142 +	r |= test_resolve("http://a/b/c/d;p?q", "//g", "http://g");
  16.143 +	r |= test_resolve("http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y");
  16.144 +	r |= test_resolve("http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y");
  16.145 +	r |= test_resolve("http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s");
  16.146 +	r |= test_resolve("http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s");
  16.147 +	r |= test_resolve("http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s");
  16.148 +	r |= test_resolve("http://a/b/c/d;p?q", ";x", "http://a/b/c/;x");
  16.149 +	r |= test_resolve("http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x");
  16.150 +	r |= test_resolve("http://a/b/c/d;p?q", "g;x?y#s",
  16.151 +			  "http://a/b/c/g;x?y#s");
  16.152 +	r |= test_resolve("http://a/b/c/d;p?q", "", "http://a/b/c/d;p?q");
  16.153 +	r |= test_resolve("http://a/b/c/d;p?q", ".", "http://a/b/c/");
  16.154 +	r |= test_resolve("http://a/b/c/d;p?q", "./", "http://a/b/c/");
  16.155 +	r |= test_resolve("http://a/b/c/d;p?q", "..", "http://a/b/");
  16.156 +	r |= test_resolve("http://a/b/c/d;p?q", "../", "http://a/b/");
  16.157 +	r |= test_resolve("http://a/b/c/d;p?q", "../g", "http://a/b/g");
  16.158 +	r |= test_resolve("http://a/b/c/d;p?q", "../..", "http://a/");
  16.159 +	r |= test_resolve("http://a/b/c/d;p?q", "../../", "http://a/");
  16.160 +	r |= test_resolve("http://a/b/c/d;p?q", "../../g", "http://a/g");
  16.161 +
  16.162 +	r |= test_resolve("http://a/b/c/d;p?q", "../../../g", "http://a/g");
  16.163 +	r |= test_resolve("http://a/b/c/d;p?q", "../../../../g", "http://a/g");
  16.164 +
  16.165 +	r |= test_resolve("http://a/b/c/d;p?q", "/./g", "http://a/g");
  16.166 +	r |= test_resolve("http://a/b/c/d;p?q", "/../g", "http://a/g");
  16.167 +	r |= test_resolve("http://a/b/c/d;p?q", "g.", "http://a/b/c/g.");
  16.168 +	r |= test_resolve("http://a/b/c/d;p?q", ".g", "http://a/b/c/.g");
  16.169 +	r |= test_resolve("http://a/b/c/d;p?q", "g..", "http://a/b/c/g..");
  16.170 +	r |= test_resolve("http://a/b/c/d;p?q", "..g", "http://a/b/c/..g");
  16.171 +
  16.172 +	r |= test_resolve("http://a/b/c/d;p?q", "./../g", "http://a/b/g");
  16.173 +	r |= test_resolve("http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/");
  16.174 +	r |= test_resolve("http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h");
  16.175 +	r |= test_resolve("http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h");
  16.176 +	r |= test_resolve("http://a/b/c/d;p?q", "g;x=1/./y",
  16.177 +			  "http://a/b/c/g;x=1/y");
  16.178 +	r |= test_resolve("http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y");
  16.179 +
  16.180 +	r |= test_resolve("http://a/b/c/d;p?q", "g?y/./x",
  16.181 +			  "http://a/b/c/g?y/./x");
  16.182 +	r |= test_resolve("http://a/b/c/d;p?q", "g?y/../x",
  16.183 +			  "http://a/b/c/g?y/../x");
  16.184 +	r |= test_resolve("http://a/b/c/d;p?q", "g#s/./x",
  16.185 +			  "http://a/b/c/g#s/./x");
  16.186 +	r |= test_resolve("http://a/b/c/d;p?q", "g#s/../x",
  16.187 +			  "http://a/b/c/g#s/../x");
  16.188 +
  16.189 +	r |= test_resolve("http://a/b/c/d;p?q", "http:g", "http:g");
  16.190 +
  16.191 +	/* From http://www.w3.org/2000/10/swap/uripath.py */
  16.192 +	r |= test_resolve("foo:xyz", "bar:abc", "bar:abc");
  16.193 +
  16.194 +	r |= test_resolve("http://example/x/y/z", "../abc",
  16.195 +			  "http://example/x/abc");
  16.196 +	r |= test_resolve("http://example2/x/y/z", "http://example/x/abc",
  16.197 +			  "http://example/x/abc");
  16.198 +	r |= test_resolve("http://ex/x/y/z", "../r", "http://ex/x/r");
  16.199 +	// "http://ex/x/y/z", "../../r", "http://ex/r");    // DanC had this.
  16.200 +	r |= test_resolve("http://ex/x/y", "q/r", "http://ex/x/q/r");
  16.201 +	r |= test_resolve("http://ex/x/y", "q/r#s", "http://ex/x/q/r#s");
  16.202 +	r |= test_resolve("http://ex/x/y", "q/r#s/t", "http://ex/x/q/r#s/t");
  16.203 +	r |= test_resolve("http://ex/x/y", "ftp://ex/x/q/r", "ftp://ex/x/q/r");
  16.204 +	r |= test_resolve("http://ex/x/y", "", "http://ex/x/y");
  16.205 +	r |= test_resolve("http://ex/x/y/", "", "http://ex/x/y/");
  16.206 +	r |= test_resolve("http://ex/x/y/pdq", "", "http://ex/x/y/pdq");
  16.207 +	r |= test_resolve("http://ex/x/y/", "z/", "http://ex/x/y/z/");
  16.208 +	r |= test_resolve("file:/swap/test/animal.rdf", "#Animal",
  16.209 +			  "file:/swap/test/animal.rdf#Animal");
  16.210 +	r |= test_resolve("file:/e/x/y/z", "../abc", "file:/e/x/abc");
  16.211 +	r |= test_resolve("file:/example2/x/y/z", "/example/x/abc",
  16.212 +			  "file:/example/x/abc");
  16.213 +	r |= test_resolve("file:/ex/x/y/z", "../r", "file:/ex/x/r");
  16.214 +	r |= test_resolve("file:/ex/x/y/z", "/r", "file:/r");
  16.215 +	r |= test_resolve("file:/ex/x/y", "q/r", "file:/ex/x/q/r");
  16.216 +	r |= test_resolve("file:/ex/x/y", "q/r#s", "file:/ex/x/q/r#s");
  16.217 +	r |= test_resolve("file:/ex/x/y", "q/r#", "file:/ex/x/q/r#");
  16.218 +	r |= test_resolve("file:/ex/x/y", "q/r#s/t", "file:/ex/x/q/r#s/t");
  16.219 +	r |= test_resolve("file:/ex/x/y", "ftp://ex/x/q/r", "ftp://ex/x/q/r");
  16.220 +	r |= test_resolve("file:/ex/x/y", "", "file:/ex/x/y");
  16.221 +	r |= test_resolve("file:/ex/x/y/", "", "file:/ex/x/y/");
  16.222 +	r |= test_resolve("file:/ex/x/y/pdq", "", "file:/ex/x/y/pdq");
  16.223 +	r |= test_resolve("file:/ex/x/y/", "z/", "file:/ex/x/y/z/");
  16.224 +	r |= test_resolve("file:/devel/WWW/2000/10/swap/test/reluri-1.n3",
  16.225 +			  "file://meetings.example.com/cal#m1",
  16.226 +			  "file://meetings.example.com/cal#m1");
  16.227 +	r |= test_resolve("file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3",
  16.228 +			  "file://meetings.example.com/cal#m1",
  16.229 +			  "file://meetings.example.com/cal#m1");
  16.230 +	r |= test_resolve("file:/some/dir/foo", "./#blort",
  16.231 +			  "file:/some/dir/#blort");
  16.232 +	r |= test_resolve("file:/some/dir/foo", "./#", "file:/some/dir/#");
  16.233 +	/* From Graham Klyne Thu, 20 Feb 2003 18:08:17 +0000 */
  16.234 +	r |= test_resolve("http://example/x/y%2Fz", "abc",
  16.235 +			  "http://example/x/abc");
  16.236 +	r |= test_resolve("http://example/x/y/z", "/x%2Fabc",
  16.237 +			  "http://example/x%2Fabc");
  16.238 +	r |= test_resolve("http://example/x/y%2Fz", "/x%2Fabc",
  16.239 +			  "http://example/x%2Fabc");
  16.240 +	r |= test_resolve("http://example/x%2Fy/z", "abc",
  16.241 +			  "http://example/x%2Fy/abc");
  16.242 +	/* Ryan Lee */
  16.243 +	r |= test_resolve("http://example/x/abc.efg", "./",
  16.244 +			  "http://example/x/");
  16.245 +
  16.246 +	exit(r ? 1 : 0);
  16.247 +}
    17.1 --- a/librazor/transaction.c	Sat Jun 11 17:56:48 2016 +0100
    17.2 +++ b/librazor/transaction.c	Mon Jul 04 10:48:18 2016 +0100
    17.3 @@ -26,11 +26,7 @@
    17.4  #include <stdint.h>
    17.5  #include <stdio.h>
    17.6  #include <string.h>
    17.7 -#include <sys/types.h>
    17.8 -#include <sys/stat.h>
    17.9  #include <unistd.h>
   17.10 -#include <fcntl.h>
   17.11 -#include <errno.h>
   17.12  #include <ctype.h>
   17.13  #include <assert.h>
   17.14  
    18.1 --- a/librazor/types/array.c	Sat Jun 11 17:56:48 2016 +0100
    18.2 +++ b/librazor/types/array.c	Mon Jul 04 10:48:18 2016 +0100
    18.3 @@ -1,6 +1,7 @@
    18.4  /*
    18.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    18.6   * Copyright (C) 2008  Red Hat, Inc
    18.7 + * Copyright (C) 2016  J. Ali Harlow <ali@juiblex.co.uk>
    18.8   *
    18.9   * This program is free software; you can redistribute it and/or modify
   18.10   * it under the terms of the GNU General Public License as published by
   18.11 @@ -23,42 +24,100 @@
   18.12  
   18.13  #include "types.h"
   18.14  
   18.15 -void
   18.16 -array_init(struct array *array)
   18.17 +void array_init(struct array *array)
   18.18  {
   18.19  	memset(array, 0, sizeof *array);
   18.20  }
   18.21  
   18.22 -void
   18.23 -array_release(struct array *array)
   18.24 +void array_release(struct array *array)
   18.25  {
   18.26  	free(array->data);
   18.27  }
   18.28  
   18.29 -void *
   18.30 -array_add(struct array *array, int size)
   18.31 +int array_set_size(struct array *array, int size)
   18.32  {
   18.33  	int alloc;
   18.34 -	void *data, *p;
   18.35 +	void *data;
   18.36  
   18.37  	if (array->alloc > 0)
   18.38  		alloc = array->alloc;
   18.39 +	else if (size > 0)
   18.40 +		alloc = 16;
   18.41  	else
   18.42 -		alloc = 16;
   18.43 +		alloc = 0;
   18.44  
   18.45 -	while (alloc < array->size + size)
   18.46 +	while (alloc < size)
   18.47  		alloc *= 2;
   18.48  
   18.49 -	if (array->alloc < alloc) {
   18.50 +	if (!alloc) {
   18.51 +		free(array->data);
   18.52 +		array->data = NULL;
   18.53 +		array->alloc = 0;
   18.54 +	} else if (array->alloc < alloc) {
   18.55  		data = realloc(array->data, alloc);
   18.56  		if (data == NULL)
   18.57 -			return 0;
   18.58 +			return -1;
   18.59  		array->data = data;
   18.60  		array->alloc = alloc;
   18.61  	}
   18.62  
   18.63 -	p = array->data + array->size;
   18.64 -	array->size += size;
   18.65 +	array->size = size;
   18.66  
   18.67 -	return p;
   18.68 +	return 0;
   18.69  }
   18.70 +
   18.71 +void *array_add(struct array *array, int size)
   18.72 +{
   18.73 +	if (array_set_size(array, array->size + size) < 0)
   18.74 +		return NULL;
   18.75 +
   18.76 +	return array->data + array->size - size;
   18.77 +}
   18.78 +
   18.79 +void ptr_array_add(struct array *ptr_array, void *data)
   18.80 +{
   18.81 +	void **ptr, **ptrend;
   18.82 +
   18.83 +	ptrend = ptr_array->data + ptr_array->size;
   18.84 +	for (ptr = ptr_array->data; ptr < ptrend; ptr++)
   18.85 +		if (!*ptr)
   18.86 +			break;
   18.87 +
   18.88 +	if (ptr == ptrend)
   18.89 +		ptr = array_add(ptr_array, sizeof *ptr);
   18.90 +
   18.91 +	*ptr = data;
   18.92 +}
   18.93 +
   18.94 +int ptr_array_find(struct array *ptr_array, void *data)
   18.95 +{
   18.96 +	void **ptr, **ptrend;
   18.97 +
   18.98 +	ptrend = ptr_array->data + ptr_array->size;
   18.99 +	for (ptr = ptr_array->data; ptr < ptrend; ptr++)
  18.100 +		if (*ptr == data)
  18.101 +			return ptr - (void **)ptr_array->data;
  18.102 +
  18.103 +	return -1;
  18.104 +}
  18.105 +
  18.106 +void ptr_array_remove_index(struct array *ptr_array, int indx)
  18.107 +{
  18.108 +	void **ptr, **ptrend;
  18.109 +
  18.110 +	ptrend = ptr_array->data + ptr_array->size;
  18.111 +
  18.112 +	ptr = (void **)ptr_array->data + indx;
  18.113 +	if (ptr >= ptrend)
  18.114 +		return;
  18.115 +	*ptr = NULL;
  18.116 +
  18.117 +	for (ptr = ptr_array->data; ptr < ptrend; ptr++)
  18.118 +		if (*ptr)
  18.119 +			break;
  18.120 +
  18.121 +	if (ptr == ptrend) {
  18.122 +		array_release(ptr_array);
  18.123 +		array_init(ptr_array);
  18.124 +	}
  18.125 +}
    19.1 --- a/librazor/types/types.h	Sat Jun 11 17:56:48 2016 +0100
    19.2 +++ b/librazor/types/types.h	Mon Jul 04 10:48:18 2016 +0100
    19.3 @@ -35,7 +35,11 @@
    19.4  
    19.5  void array_init(struct array *array);
    19.6  void array_release(struct array *array);
    19.7 +int array_set_size(struct array *array, int size);
    19.8  void *array_add(struct array *array, int size);
    19.9 +void ptr_array_add(struct array *ptr_array, void *data);
   19.10 +int ptr_array_find(struct array *ptr_array, void *data);
   19.11 +void ptr_array_remove_index(struct array *ptr_array, int indx);
   19.12  
   19.13  
   19.14  #define RAZOR_ENTRY_LAST	0x80
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/librazor/uri-io.c	Mon Jul 04 10:48:18 2016 +0100
    20.3 @@ -0,0 +1,1177 @@
    20.4 +/*
    20.5 + * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    20.6 + * Copyright (C) 2008  Red Hat, Inc
    20.7 + * Copyright (C) 2009, 2011, 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    20.8 + *
    20.9 + * This program is free software; you can redistribute it and/or modify
   20.10 + * it under the terms of the GNU General Public License as published by
   20.11 + * the Free Software Foundation; either version 2 of the License, or
   20.12 + * (at your option) any later version.
   20.13 + *
   20.14 + * This program is distributed in the hope that it will be useful,
   20.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   20.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20.17 + * GNU General Public License for more details.
   20.18 + *
   20.19 + * You should have received a copy of the GNU General Public License along
   20.20 + * with this program; if not, write to the Free Software Foundation, Inc.,
   20.21 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20.22 + */
   20.23 +
   20.24 +#include "config.h"
   20.25 +
   20.26 +#include <limits.h>
   20.27 +#include <string.h>
   20.28 +#include <sys/types.h>
   20.29 +#include <sys/stat.h>
   20.30 +#include <stdlib.h>
   20.31 +#include <stdio.h>
   20.32 +#include <stdint.h>
   20.33 +#include <errno.h>
   20.34 +#include <unistd.h>
   20.35 +#include <fcntl.h>
   20.36 +#include <dirent.h>
   20.37 +#ifdef MSWIN_API
   20.38 +#include <windows.h>
   20.39 +#include <direct.h>
   20.40 +#endif
   20.41 +#if HAVE_SYS_MMAN_H
   20.42 +#include <sys/mman.h>
   20.43 +#endif
   20.44 +#include <assert.h>
   20.45 +
   20.46 +#include "razor.h"
   20.47 +#include "types/types.h"
   20.48 +#include "razor-internal.h"
   20.49 +
   20.50 +#ifndef O_BINARY
   20.51 +#define O_BINARY	0
   20.52 +#endif
   20.53 +
   20.54 +#define strcmp0(s1, s2)		((s1) && (s2) ? strcmp(s1, s2) : \
   20.55 +				 (s1) ? 1 : (s2) ? -1 : 0)
   20.56 +
   20.57 +#define OPEN_FILE_USED		(1U<<0)
   20.58 +#define OPEN_FILE_MMAPPED	(1U<<1)
   20.59 +
   20.60 +struct open_file {
   20.61 +	void *addr;
   20.62 +	size_t length;
   20.63 +	uint32_t flags;
   20.64 +};
   20.65 +
   20.66 +struct array open_files = { 0, };
   20.67 +
   20.68 +void *razor_file_get_contents(const char *filename, size_t *length, int private,
   20.69 +			      struct razor_error **error)
   20.70 +{
   20.71 +	int fd;
   20.72 +	struct stat st;
   20.73 +	void *addr = NULL;
   20.74 +	size_t nb;
   20.75 +	ssize_t res;
   20.76 +	struct open_file *of, *ofend;
   20.77 +
   20.78 +	fd = open(filename, O_RDONLY | O_BINARY);
   20.79 +	if (fd < 0) {
   20.80 +		razor_set_error_posix(error, filename);
   20.81 +		return NULL;
   20.82 +	}
   20.83 +
   20.84 +	if (fstat(fd, &st) < 0) {
   20.85 +		razor_set_error_posix(error, filename);
   20.86 +		close(fd);
   20.87 +		return NULL;
   20.88 +	}
   20.89 +
   20.90 +	*length = st.st_size;
   20.91 +
   20.92 +	ofend = open_files.data + open_files.size;
   20.93 +	for (of = open_files.data; of < ofend; of++)
   20.94 +		if (!(of->flags & OPEN_FILE_USED))
   20.95 +			break;
   20.96 +	if (of == ofend) {
   20.97 +		of = array_add(&open_files, sizeof *of);
   20.98 +		of->flags = 0;
   20.99 +	}
  20.100 +
  20.101 +#if HAVE_SYS_MMAN_H
  20.102 +	if (!private) {
  20.103 +		addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  20.104 +		if (addr == MAP_FAILED)
  20.105 +			addr = NULL;
  20.106 +		else
  20.107 +			of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED;
  20.108 +	}
  20.109 +#endif	/* HAVE_SYS_MMAN_H */
  20.110 +	if (!addr) {
  20.111 +		addr = malloc(st.st_size);
  20.112 +		if (addr) {
  20.113 +			of->flags = OPEN_FILE_USED;
  20.114 +			nb = 0;
  20.115 +			while(nb < st.st_size) {
  20.116 +				res = read(fd, addr + nb, st.st_size - nb);
  20.117 +				if (res <= 0) {
  20.118 +					razor_set_error_posix(error, filename);
  20.119 +					free(addr);
  20.120 +					addr = NULL;
  20.121 +					break;
  20.122 +				}
  20.123 +				nb += res;
  20.124 +			}
  20.125 +		} else
  20.126 +			razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
  20.127 +					"Not enough memory");
  20.128 +	}
  20.129 +	close(fd);
  20.130 +
  20.131 +	of->addr = addr;
  20.132 +	of->length = st.st_size;
  20.133 +
  20.134 +	return addr;
  20.135 +}
  20.136 +
  20.137 +int razor_file_free_contents(void *addr, size_t length)
  20.138 +{
  20.139 +#if HAVE_SYS_MMAN_H
  20.140 +	int mmapped;
  20.141 +#endif
  20.142 +	struct open_file *of, *ofend;
  20.143 +
  20.144 +	ofend = open_files.data + open_files.size;
  20.145 +	for (of = open_files.data; of < ofend; of++)
  20.146 +		if ((of->flags & OPEN_FILE_USED) && of->addr == addr)
  20.147 +			break;
  20.148 +
  20.149 +	if (of == ofend)
  20.150 +		return -2;
  20.151 +
  20.152 +	length = of->length;
  20.153 +#if HAVE_SYS_MMAN_H
  20.154 +	mmapped = of->flags & OPEN_FILE_MMAPPED;
  20.155 +#endif
  20.156 +	of->flags &= ~OPEN_FILE_USED;
  20.157 +
  20.158 +	for (of = open_files.data; of < ofend; of++)
  20.159 +		if (of->flags & OPEN_FILE_USED)
  20.160 +			break;
  20.161 +
  20.162 +	if (of == ofend) {
  20.163 +		array_release(&open_files);
  20.164 +		array_init(&open_files);
  20.165 +	}
  20.166 +
  20.167 +#if HAVE_SYS_MMAN_H
  20.168 +	if (mmapped)
  20.169 +		return munmap(addr, length);
  20.170 +#endif
  20.171 +
  20.172 +	free(addr);
  20.173 +	return 0;
  20.174 +}
  20.175 +
  20.176 +int razor_file_mkdir(const char *path, mode_t mode, struct razor_error **error)
  20.177 +{
  20.178 +	int retval, code;
  20.179 +	struct stat buf;
  20.180 +
  20.181 +	retval = mkdir(path, mode);
  20.182 +
  20.183 +	if (retval) {
  20.184 +		/*
  20.185 +		 * Ignore the case of a pre-existing directory and give
  20.186 +		 * an explicit error message if there is something other
  20.187 +		 * than a directory already at path.
  20.188 +		 */
  20.189 +		code = errno;
  20.190 +		if (code != EEXIST || stat(path, &buf))
  20.191 +			razor_set_error(error, RAZOR_POSIX_ERROR, code, path,
  20.192 +					strerror(code));
  20.193 +		else if (!S_ISDIR(buf.st_mode))
  20.194 +			razor_set_error(error, RAZOR_POSIX_ERROR, code, path,
  20.195 +					"Not a directory");
  20.196 +	}
  20.197 +
  20.198 +	return retval;
  20.199 +}
  20.200 +
  20.201 +int razor_file_unlink(const char *path, struct razor_error **error)
  20.202 +{
  20.203 +	int retval;
  20.204 +
  20.205 +	retval = unlink(path);
  20.206 +
  20.207 +	if (retval)
  20.208 +		razor_set_error_posix(error, path);
  20.209 +
  20.210 +	return retval;
  20.211 +}
  20.212 +
  20.213 +int razor_file_open(const char *path, int flags, mode_t mode,
  20.214 +		    struct razor_error **error)
  20.215 +{
  20.216 +	int retval;
  20.217 +
  20.218 +	retval = open(path, flags, mode);
  20.219 +
  20.220 +	if (retval < 0)
  20.221 +		razor_set_error_posix(error, path);
  20.222 +
  20.223 +	return retval;
  20.224 +}
  20.225 +
  20.226 +int razor_file_move(const char *path, const char *dest,
  20.227 +		    struct razor_error **error)
  20.228 +{
  20.229 +	int retval = 0;
  20.230 +
  20.231 +#ifdef MSWIN_API
  20.232 +	wchar_t *oldbuf, *newbuf;
  20.233 +	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
  20.234 +
  20.235 +	newbuf = razor_utf8_to_utf16(dest, -1);
  20.236 +	oldbuf = razor_utf8_to_utf16(path, -1);
  20.237 +
  20.238 +	/*
  20.239 +	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
  20.240 +	 * cover every case we care about _except_ replacing an empty
  20.241 +	 * directory with a file. Calling RemoveDirectory() will deal
  20.242 +	 * with this case while having no effect in all other cases.
  20.243 +	 */
  20.244 +	(void)RemoveDirectoryW(newbuf);
  20.245 +
  20.246 +	if (!MoveFileExW(oldbuf, newbuf, flags)) {
  20.247 +		razor_set_error_mswin(error, newbuf, GetLastError());
  20.248 +		retval = -1;
  20.249 +	}
  20.250 +
  20.251 +	free(newbuf);
  20.252 +	free(oldbuf);
  20.253 +#else
  20.254 +	int code;
  20.255 +	const char *object;
  20.256 +
  20.257 +	if (rename(path, dest)) {
  20.258 +		if (error) {
  20.259 +			code = errno;
  20.260 +			if (access(path, F_OK) < 0)
  20.261 +				object = path;
  20.262 +			else
  20.263 +				object = dest;
  20.264 +			razor_set_error(error, RAZOR_POSIX_ERROR, code, object, 
  20.265 +					strerror(code));
  20.266 +		}
  20.267 +		retval = -1;
  20.268 +	}
  20.269 +#endif
  20.270 +
  20.271 +	return retval;
  20.272 +}
  20.273 +
  20.274 +#ifndef MSWIN_API
  20.275 +static char *absolute_path(const char *path)
  20.276 +{
  20.277 +	int len;
  20.278 +	char *result, *subpath, *p, *s, *t;
  20.279 +
  20.280 +	result = realpath(path, NULL);
  20.281 +
  20.282 +	if (!result && errno == ENOENT) {
  20.283 +		p = strdup(path);
  20.284 +		s = strrchr(p, '/');
  20.285 +
  20.286 +		while (s) {
  20.287 +			if (s == p) {
  20.288 +				result = strdup("/");
  20.289 +				break;
  20.290 +			}
  20.291 +
  20.292 +			*s = '\0';
  20.293 +			subpath = realpath(p, NULL);
  20.294 +
  20.295 +			if (subpath) {
  20.296 +				*s = '/';
  20.297 +				len = strlen(subpath);
  20.298 +				result = malloc(len + strlen(s) + 1);
  20.299 +				memcpy(result, subpath, len);
  20.300 +				strcpy(result + len, s);
  20.301 +				free(subpath);
  20.302 +				break;
  20.303 +			} else if (errno != ENOENT)
  20.304 +				break;
  20.305 +
  20.306 +			t = strrchr(p, '/');
  20.307 +			*s = '/';
  20.308 +			s = t;
  20.309 +		}
  20.310 +
  20.311 +		if (!s)
  20.312 +			result = realpath(".", NULL);
  20.313 +
  20.314 +		free(p);
  20.315 +	}
  20.316 +
  20.317 +	return result;
  20.318 +}
  20.319 +#endif
  20.320 +
  20.321 +int razor_file_is_directory(const char *path, struct razor_error **error)
  20.322 +{
  20.323 +	struct stat st;
  20.324 +
  20.325 +	if (stat(path, &st) < 0) {
  20.326 +		razor_set_error_posix(error, path);
  20.327 +		return -1;
  20.328 +	}
  20.329 +
  20.330 +	return !!S_ISDIR(st.st_mode);
  20.331 +}
  20.332 +
  20.333 +char *razor_file_mkdtemp_near(const char *path, const char *template,
  20.334 +			      struct razor_error **error)
  20.335 +{
  20.336 +	char *retval;
  20.337 +
  20.338 +#ifdef MSWIN_API
  20.339 +	if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\'
  20.340 +	    && strchr(path+3,'\\')) {
  20.341 +		/* We have a UNC path: \\servername\sharename... */
  20.342 +		const char *sharename, *root;
  20.343 +		int disklen;
  20.344 +
  20.345 +		sharename = strchr(path+3,'\\')+1;
  20.346 +		root = strchr(sharename,'\\');
  20.347 +		if (root)
  20.348 +		    disklen = root - path;
  20.349 +		else
  20.350 +		    disklen = strlen(path);
  20.351 +
  20.352 +		retval = malloc(disklen + 1 + strlen(template) + 1);
  20.353 +		memcpy(retval, path, disklen);
  20.354 +		retval[disklen] = '\\';
  20.355 +		strcpy(retval + disklen + 1, template);
  20.356 +	} else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') &&
  20.357 +		    path[1]==':') {
  20.358 +		retval = malloc(3 + strlen(template) + 1);
  20.359 +		retval[0] = path[0];
  20.360 +		retval[1] = ':';
  20.361 +		retval[2] = '\\';
  20.362 +		strcpy(retval + 3, template);
  20.363 +	} else {
  20.364 +		DWORD n;
  20.365 +		wchar_t *buf;
  20.366 +		char *dir;
  20.367 +
  20.368 +		n = GetCurrentDirectoryW(0, NULL);
  20.369 +		buf = malloc(n * sizeof(wchar_t));
  20.370 +
  20.371 +		if (GetCurrentDirectoryW(n, buf)) {
  20.372 +			dir = razor_utf16_to_utf8(buf, n - 1);
  20.373 +			free(buf);
  20.374 +			retval = razor_file_mkdtemp_near(dir, template, error);
  20.375 +			free(dir);
  20.376 +			return retval;
  20.377 +		} else {
  20.378 +			retval = malloc(3 + strlen(template) + 1);
  20.379 +			retval[0] = 'C';
  20.380 +			retval[1] = ':';
  20.381 +			retval[2] = '\\';
  20.382 +			strcpy(retval + 3, template);
  20.383 +		}
  20.384 +
  20.385 +		free(buf);
  20.386 +	}
  20.387 +#else
  20.388 +	/*
  20.389 +	 * Find the mount point (assuming we can write to the
  20.390 +	 * whole filesystem). Otherwise stop at the first
  20.391 +	 * unwritable directory and take one step back.
  20.392 +	 */
  20.393 +	char *s, *abspath, saved;
  20.394 +	int len, can_step_back = 0;
  20.395 +	dev_t filesystem;
  20.396 +	struct stat buf;
  20.397 +
  20.398 +	abspath = absolute_path(path);
  20.399 +	if (!abspath) {
  20.400 +		razor_set_error_posix(error, path);
  20.401 +		return NULL;
  20.402 +	}
  20.403 +
  20.404 +	if (stat(abspath, &buf) < 0) {
  20.405 +		if (errno == ENOENT)
  20.406 +			filesystem = 0;
  20.407 +		else {
  20.408 +			razor_set_error_posix(error, abspath);
  20.409 +			free(abspath);
  20.410 +			return NULL;
  20.411 +		}
  20.412 +	} else
  20.413 +		filesystem = buf.st_dev;
  20.414 +
  20.415 +	len = strlen(abspath);
  20.416 +	while(len > 1 && (s = strrchr(abspath, '/'))) {
  20.417 +		if (s == abspath) {
  20.418 +			saved = s[1];
  20.419 +			s[1] = '\0';
  20.420 +			len = s + 1 - abspath;
  20.421 +		} else {
  20.422 +			s[0] = '\0';
  20.423 +			len = s - abspath;
  20.424 +		}
  20.425 +
  20.426 +		if (stat(abspath, &buf) < 0) {
  20.427 +			if (errno == ENOENT)
  20.428 +				continue;
  20.429 +			else {
  20.430 +			    razor_set_error_posix(error, abspath);
  20.431 +			    free(abspath);
  20.432 +			    return NULL;
  20.433 +			}
  20.434 +		} else if (!filesystem)
  20.435 +			filesystem = buf.st_dev;
  20.436 +
  20.437 +		if (buf.st_dev != filesystem || access(abspath, W_OK)) {
  20.438 +			if (can_step_back) {
  20.439 +				if (s == abspath)
  20.440 +					s[1] = saved;
  20.441 +				else
  20.442 +					s[0] = '/';
  20.443 +			}
  20.444 +			len = strlen(abspath);
  20.445 +			break;
  20.446 +		} else
  20.447 +			can_step_back = 1;
  20.448 +	}
  20.449 +
  20.450 +	if (len == 1)
  20.451 +		len = 0;	/* Avoid an unslightly double slash. */
  20.452 +	retval = malloc(len + 1 + strlen(template) + 1);
  20.453 +	memcpy(retval, abspath, len);
  20.454 +	retval[len] = '/';
  20.455 +	strcpy(retval + len + 1, template);
  20.456 +
  20.457 +	free(abspath);
  20.458 +#endif
  20.459 +
  20.460 +	if (!mkdtemp(retval)) {
  20.461 +		int err = errno;
  20.462 +
  20.463 +#ifdef EACCES
  20.464 +		if (err == EACCES) {
  20.465 +			char *s = strdup(template);
  20.466 +
  20.467 +#ifndef MSWIN_API
  20.468 +			if (stat(".", &buf) < 0) {
  20.469 +				razor_set_error_posix(error, ".");
  20.470 +				free(s);
  20.471 +				free(retval);
  20.472 +				return NULL;
  20.473 +			}
  20.474 +			if (buf.st_dev != filesystem)
  20.475 +				/*
  20.476 +				 * Don't use a different filesystem. It will
  20.477 +				 * only fail later on (in rename) and cause
  20.478 +				 * an unhelpful error message (EXDEV).
  20.479 +				 */
  20.480 +				free(s);
  20.481 +			else
  20.482 +#endif
  20.483 +			if (mkdtemp(s)) {
  20.484 +				free(retval);
  20.485 +				retval = s;
  20.486 +				return retval;
  20.487 +			} else
  20.488 +				free(s);
  20.489 +		}
  20.490 +#endif
  20.491 +
  20.492 +		razor_set_error(error, RAZOR_POSIX_ERROR, err, retval,
  20.493 +				strerror(err));
  20.494 +
  20.495 +		free(retval);
  20.496 +		retval = NULL;
  20.497 +	}
  20.498 +
  20.499 +	return retval;
  20.500 +}
  20.501 +
  20.502 +struct open_dir {
  20.503 +	uint32_t flags;
  20.504 +#ifdef MSWIN_API
  20.505 +	_WDIR *dp;
  20.506 +	wchar_t *path2;
  20.507 +#else
  20.508 +	DIR *dp;
  20.509 +	char *path;
  20.510 +#endif
  20.511 +};
  20.512 +
  20.513 +#define OPEN_DIR_USED		(1U<<0)
  20.514 +
  20.515 +struct array open_dirs = { 0, };
  20.516 +
  20.517 +void *razor_file_opendir(const char *path, struct razor_error **error)
  20.518 +{
  20.519 +	struct open_dir *od, *odend;
  20.520 +
  20.521 +	odend = open_dirs.data + open_dirs.size;
  20.522 +	for (od = open_dirs.data; od < odend; od++)
  20.523 +		if (!(od->flags & OPEN_DIR_USED))
  20.524 +			break;
  20.525 +	if (od == odend) {
  20.526 +		od = array_add(&open_dirs, sizeof *od);
  20.527 +		od->flags = 0;
  20.528 +	}
  20.529 +
  20.530 +#ifdef MSWIN_API
  20.531 +	od->path2 = razor_utf8_to_utf16(path, -1);
  20.532 +	od->dp = _wopendir(od->path2);
  20.533 +#else
  20.534 +	od->path = strdup(path);
  20.535 +	od->dp = opendir(od->path);
  20.536 +#endif
  20.537 +
  20.538 +	if (!od->dp) {
  20.539 +#ifdef MSWIN_API
  20.540 +		razor_set_error_mswin(error, od->path2, GetLastError());
  20.541 +		free(od->path2);
  20.542 +#else
  20.543 +		razor_set_error_posix(error, od->path);
  20.544 +		free(od->path);
  20.545 +#endif
  20.546 +		return NULL;
  20.547 +	}
  20.548 +
  20.549 +	od->flags = OPEN_DIR_USED;
  20.550 +	return od;
  20.551 +}
  20.552 +
  20.553 +char *razor_file_readdir(void *dp, struct razor_error **error)
  20.554 +{
  20.555 +	struct open_dir *od = dp, *odend;
  20.556 +#ifdef MSWIN_API
  20.557 +	struct _wdirent *dirp;
  20.558 +	char *path;
  20.559 +#else
  20.560 +	struct dirent *dirp;
  20.561 +#endif
  20.562 +
  20.563 +	odend = open_dirs.data + open_dirs.size;
  20.564 +	if (dp < open_dirs.data || od >= odend || !(od->flags & OPEN_DIR_USED))
  20.565 +		return (char *)-1;
  20.566 +
  20.567 +	errno = 0;
  20.568 +
  20.569 +#ifdef MSWIN_API
  20.570 +	while((dirp = _wreaddir(od->dp))) {
  20.571 +		path = razor_utf16_to_utf8(dirp->d_name, -1);
  20.572 +		if (strcmp(path, ".") && strcmp(path, ".."))
  20.573 +			return path;
  20.574 +		else
  20.575 +			free(path);
  20.576 +	}
  20.577 +#else
  20.578 +	while((dirp = readdir(od->dp)))
  20.579 +		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, ".."))
  20.580 +			return strdup(dirp->d_name);
  20.581 +#endif
  20.582 +
  20.583 +	if (errno) {
  20.584 +#ifdef MSWIN_API
  20.585 +		razor_set_error_mswin(error, od->path2, GetLastError());
  20.586 +#else
  20.587 +		razor_set_error_posix(error, od->path);
  20.588 +#endif
  20.589 +	}
  20.590 +
  20.591 +	return NULL;
  20.592 +}
  20.593 +
  20.594 +int razor_file_closedir(void *dp, struct razor_error **error)
  20.595 +{
  20.596 +	struct open_dir *od = dp, *odend;
  20.597 +	int retval;
  20.598 +
  20.599 +	odend = open_dirs.data + open_dirs.size;
  20.600 +	if (dp < open_dirs.data || od >= odend || !(od->flags & OPEN_DIR_USED))
  20.601 +		return -2;
  20.602 +
  20.603 +#ifdef MSWIN_API
  20.604 +	/*
  20.605 +	 * I can't find documentation to state that _wclosedir()
  20.606 +	 * returns -1 on failure, so be paranoid.
  20.607 +	 */
  20.608 +	retval = _wclosedir(od->dp) ? -1 : 0;
  20.609 +#else
  20.610 +	retval = closedir(od->dp);
  20.611 +#endif
  20.612 +
  20.613 +	if (retval) {
  20.614 +#ifdef MSWIN_API
  20.615 +		razor_set_error_mswin(error, od->path2, GetLastError());
  20.616 +#else
  20.617 +		razor_set_error_posix(error, od->path);
  20.618 +#endif
  20.619 +	}
  20.620 +
  20.621 +#ifdef MSWIN_API
  20.622 +	free(od->path2);
  20.623 +#else
  20.624 +	free(od->path);
  20.625 +#endif
  20.626 +
  20.627 +	od->flags &= ~OPEN_DIR_USED;
  20.628 +
  20.629 +	for (od = open_dirs.data; od < odend; od++)
  20.630 +		if (od->flags & OPEN_DIR_USED)
  20.631 +			break;
  20.632 +
  20.633 +	if (od == odend) {
  20.634 +		array_release(&open_dirs);
  20.635 +		array_init(&open_dirs);
  20.636 +	}
  20.637 +
  20.638 +	return retval;
  20.639 +}
  20.640 +
  20.641 +struct razor_uri_vtable_entry {
  20.642 +	struct razor_uri_vtable vtable;
  20.643 +	char *scheme;
  20.644 +	struct array open_files, open_directories;
  20.645 +};
  20.646 +
  20.647 +static struct array razor_uri_vtable_entries;
  20.648 +
  20.649 +static struct razor_uri_vtable_entry *
  20.650 +  razor_uri_get_vtable_entry(const char *scheme)
  20.651 +{
  20.652 +	struct razor_uri_vtable_entry *entry, *eend, *fallback = NULL;
  20.653 +
  20.654 +	eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
  20.655 +	for(entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
  20.656 +		if (!strcmp0(entry->scheme, scheme))
  20.657 +			return entry;
  20.658 +		else if (!entry->scheme)
  20.659 +			fallback = entry;
  20.660 +	}
  20.661 +
  20.662 +	return fallback;
  20.663 +}
  20.664 +
  20.665 +int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error)
  20.666 +{
  20.667 +	int retval;
  20.668 +	char *path;
  20.669 +	struct razor_uri ru;
  20.670 +	struct razor_uri_vtable_entry *entry;
  20.671 +	struct razor_error *tmp_error = NULL;
  20.672 +
  20.673 +	if (razor_uri_parse(&ru, uri, error))
  20.674 +		return -1;
  20.675 +
  20.676 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
  20.677 +
  20.678 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.679 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.680 +		razor_error_free(tmp_error);
  20.681 +	else if (!path) {
  20.682 +		razor_propagate_error(error, tmp_error, NULL);
  20.683 +		razor_uri_destroy(&ru);
  20.684 +		return -1;
  20.685 +	}
  20.686 +
  20.687 +	if (path) {
  20.688 +		razor_uri_destroy(&ru);
  20.689 +		retval = razor_file_mkdir(path, mode, error);
  20.690 +		free(path);
  20.691 +	} else {
  20.692 +		entry = razor_uri_get_vtable_entry(ru.scheme);
  20.693 +		razor_uri_destroy(&ru);
  20.694 +		if (!entry || !entry->vtable.mkdir) {
  20.695 +			retval = -1;
  20.696 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.697 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.698 +					uri, "No URI handler installed");
  20.699 +		} else
  20.700 +			retval = entry->vtable.mkdir(uri, mode, error);
  20.701 +	}
  20.702 +
  20.703 +	return retval;
  20.704 +}
  20.705 +
  20.706 +int razor_uri_unlink(const char *uri, struct razor_error **error)
  20.707 +{
  20.708 +	int retval;
  20.709 +	char *path;
  20.710 +	struct razor_uri ru;
  20.711 +	struct razor_uri_vtable_entry *entry;
  20.712 +	struct razor_error *tmp_error = NULL;
  20.713 +
  20.714 +	if (razor_uri_parse(&ru, uri, error))
  20.715 +		return -1;
  20.716 +
  20.717 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
  20.718 +
  20.719 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.720 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.721 +		razor_error_free(tmp_error);
  20.722 +	else if (!path) {
  20.723 +		razor_propagate_error(error, tmp_error, NULL);
  20.724 +		razor_uri_destroy(&ru);
  20.725 +		return -1;
  20.726 +	}
  20.727 +
  20.728 +	if (path) {
  20.729 +		razor_uri_destroy(&ru);
  20.730 +		retval = razor_file_unlink(path, error);
  20.731 +		free(path);
  20.732 +	} else {
  20.733 +		entry = razor_uri_get_vtable_entry(ru.scheme);
  20.734 +		razor_uri_destroy(&ru);
  20.735 +		if (!entry || !entry->vtable.unlink) {
  20.736 +			retval = -1;
  20.737 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.738 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.739 +					uri, "No URI handler installed");
  20.740 +		} else
  20.741 +			retval = entry->vtable.unlink(uri, error);
  20.742 +	}
  20.743 +
  20.744 +	return retval;
  20.745 +}
  20.746 +
  20.747 +int razor_uri_open(const char *uri, int flags, mode_t mode,
  20.748 +		   struct razor_error **error)
  20.749 +{
  20.750 +	int retval;
  20.751 +	char *path;
  20.752 +	struct razor_uri ru;
  20.753 +	struct razor_uri_vtable_entry *entry;
  20.754 +	struct razor_error *tmp_error = NULL;
  20.755 +
  20.756 +	if (razor_uri_parse(&ru, uri, error))
  20.757 +		return -1;
  20.758 +
  20.759 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
  20.760 +
  20.761 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.762 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.763 +		razor_error_free(tmp_error);
  20.764 +	else if (!path) {
  20.765 +		razor_propagate_error(error, tmp_error, NULL);
  20.766 +		razor_uri_destroy(&ru);
  20.767 +		return -1;
  20.768 +	}
  20.769 +
  20.770 +	if (path) {
  20.771 +		razor_uri_destroy(&ru);
  20.772 +		retval = razor_file_open(path, flags, mode, error);
  20.773 +		free(path);
  20.774 +	} else {
  20.775 +		entry = razor_uri_get_vtable_entry(ru.scheme);
  20.776 +		razor_uri_destroy(&ru);
  20.777 +		if (!entry || !entry->vtable.open) {
  20.778 +			retval = -1;
  20.779 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.780 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.781 +					uri, "No URI handler installed");
  20.782 +		} else
  20.783 +			retval = entry->vtable.open(uri, flags, mode, error);
  20.784 +	}
  20.785 +
  20.786 +	return retval;
  20.787 +}
  20.788 +
  20.789 +int razor_uri_move(const char *src_uri, const char *dst_uri,
  20.790 +		   struct razor_error **error)
  20.791 +{
  20.792 +	int retval;
  20.793 +	char *src_path, *dst_path;
  20.794 +	struct razor_uri src_ru, dst_ru;
  20.795 +	struct razor_uri_vtable_entry *entry;
  20.796 +	struct razor_error *tmp_error = NULL;
  20.797 +
  20.798 +	if (razor_uri_parse(&src_ru, src_uri, error) ||
  20.799 +	    razor_uri_parse(&dst_ru, dst_uri, error))
  20.800 +		return -1;
  20.801 +
  20.802 +	src_path = razor_path_from_parsed_uri(&src_ru, &tmp_error);
  20.803 +
  20.804 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.805 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.806 +		razor_error_free(tmp_error);
  20.807 +	else if (!src_path) {
  20.808 +		razor_propagate_error(error, tmp_error, NULL);
  20.809 +		razor_uri_destroy(&src_ru);
  20.810 +		return -1;
  20.811 +	}
  20.812 +
  20.813 +	dst_path = razor_path_from_parsed_uri(&dst_ru, &tmp_error);
  20.814 +
  20.815 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.816 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.817 +		razor_error_free(tmp_error);
  20.818 +	else if (!dst_path) {
  20.819 +		razor_propagate_error(error, tmp_error, NULL);
  20.820 +		razor_uri_destroy(&dst_ru);
  20.821 +		razor_uri_destroy(&src_ru);
  20.822 +		free(src_path);
  20.823 +		return -1;
  20.824 +	}
  20.825 +
  20.826 +	if (src_path && dst_path)
  20.827 +		retval = razor_file_move(src_path, dst_path, error);
  20.828 +	else {
  20.829 +		if (!strcmp(src_ru.scheme, dst_ru.scheme))
  20.830 +			entry = razor_uri_get_vtable_entry(src_ru.scheme);
  20.831 +		else
  20.832 +			entry = NULL;
  20.833 +		if (entry && entry->vtable.move)
  20.834 +			retval = entry->vtable.move(src_uri, dst_uri, error);
  20.835 +		else if (strcmp(src_ru.scheme, dst_ru.scheme)) {
  20.836 +			retval = -1;
  20.837 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.838 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.839 +					dst_uri, "Cross-scheme URI move");
  20.840 +		} else {
  20.841 +			retval = -1;
  20.842 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.843 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.844 +					src_path ? dst_uri : src_uri,
  20.845 +					"No URI handler installed");
  20.846 +		}
  20.847 +	}
  20.848 +
  20.849 +	razor_uri_destroy(&src_ru);
  20.850 +	razor_uri_destroy(&dst_ru);
  20.851 +	free(src_path);
  20.852 +	free(dst_path);
  20.853 +
  20.854 +	return retval;
  20.855 +}
  20.856 +
  20.857 +void *razor_uri_get_contents(const char *uri, size_t *length, int private,
  20.858 +			     struct razor_error **error)
  20.859 +{
  20.860 +	void *retval;
  20.861 +	char *path;
  20.862 +	struct razor_uri ru;
  20.863 +	struct razor_uri_vtable_entry *entry;
  20.864 +	struct razor_error *tmp_error = NULL;
  20.865 +
  20.866 +	if (razor_uri_parse(&ru, uri, error))
  20.867 +		return NULL;
  20.868 +
  20.869 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
  20.870 +
  20.871 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.872 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.873 +		razor_error_free(tmp_error);
  20.874 +	else if (!path) {
  20.875 +		razor_propagate_error(error, tmp_error, NULL);
  20.876 +		razor_uri_destroy(&ru);
  20.877 +		return NULL;
  20.878 +	}
  20.879 +
  20.880 +	if (path) {
  20.881 +		razor_uri_destroy(&ru);
  20.882 +		retval = razor_file_get_contents(path, length, private, error);
  20.883 +		free(path);
  20.884 +	} else {
  20.885 +		entry = razor_uri_get_vtable_entry(ru.scheme);
  20.886 +		razor_uri_destroy(&ru);
  20.887 +		if (!entry || !entry->vtable.get_contents) {
  20.888 +			retval = NULL;
  20.889 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.890 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.891 +					uri, "No URI handler installed");
  20.892 +		} else {
  20.893 +			retval = entry->vtable.get_contents(uri, length,
  20.894 +							    private, error);
  20.895 +			if (retval)
  20.896 +				ptr_array_add(&entry->open_files, retval);
  20.897 +		}
  20.898 +	}
  20.899 +
  20.900 +	return retval;
  20.901 +}
  20.902 +
  20.903 +int razor_uri_free_contents(void *addr, size_t length)
  20.904 +{
  20.905 +	int retval, of;
  20.906 +	struct razor_uri_vtable_entry *entry, *eend;
  20.907 +
  20.908 +	if (!addr)
  20.909 +		return 0;
  20.910 +
  20.911 +	retval = razor_file_free_contents(addr, length);
  20.912 +
  20.913 +	if (retval != -2)
  20.914 +		return retval;
  20.915 +
  20.916 +	eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
  20.917 +	for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
  20.918 +		of = ptr_array_find(&entry->open_files, addr);
  20.919 +		if (of >= 0) {
  20.920 +			if (entry->vtable.free_contents)
  20.921 +				retval = entry->vtable.free_contents(addr,
  20.922 +								     length);
  20.923 +			ptr_array_remove_index(&entry->open_files, of);
  20.924 +			break;
  20.925 +		}
  20.926 +	}
  20.927 +
  20.928 +	return retval;
  20.929 +}
  20.930 +
  20.931 +int razor_uri_is_directory(const char *uri, struct razor_error **error)
  20.932 +{
  20.933 +	int retval;
  20.934 +	char *path;
  20.935 +	struct razor_uri ru;
  20.936 +	struct razor_uri_vtable_entry *entry;
  20.937 +	struct razor_error *tmp_error = NULL;
  20.938 +
  20.939 +	if (razor_uri_parse(&ru, uri, error))
  20.940 +		return -1;
  20.941 +
  20.942 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
  20.943 +
  20.944 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.945 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.946 +		razor_error_free(tmp_error);
  20.947 +	else if (!path) {
  20.948 +		razor_propagate_error(error, tmp_error, NULL);
  20.949 +		razor_uri_destroy(&ru);
  20.950 +		return -1;
  20.951 +	}
  20.952 +
  20.953 +	if (path) {
  20.954 +		razor_uri_destroy(&ru);
  20.955 +		retval = razor_file_is_directory(path, error);
  20.956 +		free(path);
  20.957 +	} else {
  20.958 +		entry = razor_uri_get_vtable_entry(ru.scheme);
  20.959 +		razor_uri_destroy(&ru);
  20.960 +		if (!entry || !entry->vtable.is_directory) {
  20.961 +			retval = -1;
  20.962 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  20.963 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
  20.964 +					uri, "No URI handler installed");
  20.965 +		} else
  20.966 +			retval = entry->vtable.is_directory(uri, error);
  20.967 +	}
  20.968 +
  20.969 +	return retval;
  20.970 +}
  20.971 +
  20.972 +char *razor_uri_mkdtemp_near(const char *uri, const char *template,
  20.973 +			     struct razor_error **error)
  20.974 +{
  20.975 +	char *retval, *s;
  20.976 +	char *path;
  20.977 +	struct razor_uri ru;
  20.978 +	struct razor_uri_vtable_entry *entry;
  20.979 +	struct razor_error *tmp_error = NULL;
  20.980 +
  20.981 +	if (razor_uri_parse(&ru, uri, error))
  20.982 +		return NULL;
  20.983 +
  20.984 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
  20.985 +
  20.986 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
  20.987 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
  20.988 +		razor_error_free(tmp_error);
  20.989 +	else if (!path) {
  20.990 +		razor_propagate_error(error, tmp_error, NULL);
  20.991 +		razor_uri_destroy(&ru);
  20.992 +		return NULL;
  20.993 +	}
  20.994 +
  20.995 +	if (path) {
  20.996 +		razor_uri_destroy(&ru);
  20.997 +		s = razor_file_mkdtemp_near(path, template, error);
  20.998 +		retval = razor_path_to_uri(s);
  20.999 +		free(s);
 20.1000 +		free(path);
 20.1001 +	} else {
 20.1002 +		entry = razor_uri_get_vtable_entry(ru.scheme);
 20.1003 +		razor_uri_destroy(&ru);
 20.1004 +		if (!entry || !entry->vtable.mkdtemp_near) {
 20.1005 +			retval = NULL;
 20.1006 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1007 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
 20.1008 +					uri, "No URI handler installed");
 20.1009 +		} else
 20.1010 +			retval = entry->vtable.mkdtemp_near(uri, template,
 20.1011 +							    error);
 20.1012 +	}
 20.1013 +
 20.1014 +	return retval;
 20.1015 +}
 20.1016 +
 20.1017 +void *razor_uri_opendir(const char *uri, struct razor_error **error)
 20.1018 +{
 20.1019 +	void *retval;
 20.1020 +	char *path;
 20.1021 +	struct razor_uri ru;
 20.1022 +	struct razor_uri_vtable_entry *entry;
 20.1023 +	struct razor_error *tmp_error = NULL;
 20.1024 +
 20.1025 +	if (razor_uri_parse(&ru, uri, error))
 20.1026 +		return NULL;
 20.1027 +
 20.1028 +	path = razor_path_from_parsed_uri(&ru, &tmp_error);
 20.1029 +
 20.1030 +	if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
 20.1031 +	    RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
 20.1032 +		razor_error_free(tmp_error);
 20.1033 +	else if (!path) {
 20.1034 +		razor_propagate_error(error, tmp_error, NULL);
 20.1035 +		razor_uri_destroy(&ru);
 20.1036 +		return NULL;
 20.1037 +	}
 20.1038 +
 20.1039 +	if (path) {
 20.1040 +		razor_uri_destroy(&ru);
 20.1041 +		retval = razor_file_opendir(path, error);
 20.1042 +		free(path);
 20.1043 +	} else {
 20.1044 +		entry = razor_uri_get_vtable_entry(ru.scheme);
 20.1045 +		razor_uri_destroy(&ru);
 20.1046 +		if (!entry || !entry->vtable.opendir) {
 20.1047 +			retval = NULL;
 20.1048 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1049 +					RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
 20.1050 +					uri, "No URI handler installed");
 20.1051 +		} else {
 20.1052 +			retval = entry->vtable.opendir(uri, error);
 20.1053 +			if (retval)
 20.1054 +				ptr_array_add(&entry->open_directories, retval);
 20.1055 +		}
 20.1056 +	}
 20.1057 +
 20.1058 +	return retval;
 20.1059 +}
 20.1060 +
 20.1061 +char *razor_uri_readdir(void *dir, struct razor_error **error)
 20.1062 +{
 20.1063 +	int od;
 20.1064 +	char *retval;
 20.1065 +	struct razor_uri_vtable_entry *entry, *eend;
 20.1066 +
 20.1067 +	retval = razor_file_readdir(dir, error);
 20.1068 +
 20.1069 +	if (retval != (char *)-1)
 20.1070 +		return retval;
 20.1071 +
 20.1072 +	eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
 20.1073 +	for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
 20.1074 +		od = ptr_array_find(&entry->open_directories, dir);
 20.1075 +		if (od >= 0) {
 20.1076 +			if (entry->vtable.readdir)
 20.1077 +				retval = entry->vtable.readdir(dir, error);
 20.1078 +			break;
 20.1079 +		}
 20.1080 +	}
 20.1081 +
 20.1082 +	if (retval == (char *)-1) {
 20.1083 +		retval = NULL;
 20.1084 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1085 +				RAZOR_GENERAL_ERROR_FAILED, NULL,
 20.1086 +				"Invalid directory handle");
 20.1087 +	}
 20.1088 +
 20.1089 +	return retval;
 20.1090 +}
 20.1091 +
 20.1092 +int razor_uri_closedir(void *dir, struct razor_error **error)
 20.1093 +{
 20.1094 +	int od;
 20.1095 +	int retval;
 20.1096 +	struct razor_uri_vtable_entry *entry, *eend;
 20.1097 +
 20.1098 +	retval = razor_file_closedir(dir, error);
 20.1099 +
 20.1100 +	if (retval != -2)
 20.1101 +		return retval;
 20.1102 +
 20.1103 +	eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
 20.1104 +	for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
 20.1105 +		od = ptr_array_find(&entry->open_directories, dir);
 20.1106 +		if (od >= 0) {
 20.1107 +			if (entry->vtable.closedir)
 20.1108 +				retval = entry->vtable.closedir(dir, error);
 20.1109 +			break;
 20.1110 +		}
 20.1111 +	}
 20.1112 +
 20.1113 +	if (retval == -2)
 20.1114 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1115 +				RAZOR_GENERAL_ERROR_FAILED, NULL,
 20.1116 +				"Invalid directory handle");
 20.1117 +
 20.1118 +	return retval;
 20.1119 +}
 20.1120 +
 20.1121 +RAZOR_EXPORT int razor_uri_set_vtable(const char *scheme,
 20.1122 +  struct razor_uri_vtable *vtable, struct razor_error **error)
 20.1123 +{
 20.1124 +	struct razor_uri_vtable_entry *entry, *eend;
 20.1125 +
 20.1126 +	if (!strcmp0(scheme, "file")) {
 20.1127 +		/*
 20.1128 +		 * There's no fundamental reason why we couldn't support
 20.1129 +		 * this, but it's a lot of work without any obvious need.
 20.1130 +		 */
 20.1131 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1132 +				RAZOR_GENERAL_ERROR_FAILED, scheme,
 20.1133 +				"Can't override file scheme handler");
 20.1134 +		return -1;
 20.1135 +	}
 20.1136 +
 20.1137 +	if (vtable->structure_size < sizeof(struct razor_uri_vtable)) {
 20.1138 +		/*
 20.1139 +		 * A future version of the API might add vfuncs to the
 20.1140 +		 * table (which we ignore), but won't remove any.
 20.1141 +		 */
 20.1142 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1143 +				RAZOR_GENERAL_ERROR_FAILED, scheme,
 20.1144 +				"Invalid vtable structure size");
 20.1145 +		return -1;
 20.1146 +	}
 20.1147 +
 20.1148 +	eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
 20.1149 +	for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
 20.1150 +		if (!strcmp0(entry->scheme, scheme))
 20.1151 +			break;
 20.1152 +	}
 20.1153 +
 20.1154 +	if (entry == eend) {
 20.1155 +		if (!vtable)
 20.1156 +			return 0;
 20.1157 +		entry = array_add(&razor_uri_vtable_entries, sizeof *entry);
 20.1158 +		entry->scheme = scheme ? strdup(scheme) : NULL;
 20.1159 +		array_init(&entry->open_files);
 20.1160 +		array_init(&entry->open_directories);
 20.1161 +	} else if (entry->open_files.size || entry->open_directories.size) {
 20.1162 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
 20.1163 +				RAZOR_GENERAL_ERROR_FAILED, scheme,
 20.1164 +				"URI handler busy");
 20.1165 +		return -1;
 20.1166 +	}
 20.1167 +
 20.1168 +	if (vtable) {
 20.1169 +		entry->vtable = *vtable;
 20.1170 +		entry->vtable.structure_size = sizeof(struct razor_uri_vtable);
 20.1171 +	} else {
 20.1172 +		free(entry->scheme);
 20.1173 +		if (entry + 1 < eend)
 20.1174 +			memmove(entry, entry + 1, eend - (entry + 1));
 20.1175 +		array_set_size(&razor_uri_vtable_entries,
 20.1176 +			       razor_uri_vtable_entries.size - sizeof *entry);
 20.1177 +	}
 20.1178 +
 20.1179 +	return 0;
 20.1180 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/librazor/uri.c	Mon Jul 04 10:48:18 2016 +0100
    21.3 @@ -0,0 +1,957 @@
    21.4 +/*
    21.5 + * Copyright (C) 2016  J. Ali Harlow <ali@juiblex.co.uk>
    21.6 + *
    21.7 + * This program is free software; you can redistribute it and/or modify
    21.8 + * it under the terms of the GNU General Public License as published by
    21.9 + * the Free Software Foundation; either version 2 of the License, or
   21.10 + * (at your option) any later version.
   21.11 + *
   21.12 + * This program is distributed in the hope that it will be useful,
   21.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   21.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   21.15 + * GNU General Public License for more details.
   21.16 + *
   21.17 + * You should have received a copy of the GNU General Public License along
   21.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
   21.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   21.20 + */
   21.21 +
   21.22 +#include "config.h"
   21.23 +
   21.24 +#undef DEBUG
   21.25 +
   21.26 +#include <stdlib.h>
   21.27 +#include <string.h>
   21.28 +#include "razor.h"
   21.29 +#include "types/types.h"
   21.30 +#include "razor-internal.h"
   21.31 +#include "uri.h"
   21.32 +
   21.33 +/*
   21.34 + * Following RFC 3986 § 3.
   21.35 + * Note that we don't validate queries or fragments.
   21.36 + */
   21.37 +
   21.38 +#define strdup0(s)			((s) ? strdup(s) : NULL)
   21.39 +
   21.40 +#define string_str(str)			((char *)(str)->data)
   21.41 +
   21.42 +#define string_init(str)		do { \
   21.43 +						char *_p; \
   21.44 +						array_init(str); \
   21.45 +						_p = array_add(str, 1); \
   21.46 +						*_p = '\0'; \
   21.47 +					} while(0)
   21.48 +
   21.49 +#define string_append_len(str, s, len)	do { \
   21.50 +						char *_p; \
   21.51 +						_p = array_add(str, len); \
   21.52 +						_p--; \
   21.53 +						strncpy(_p, s, len); \
   21.54 +						_p[(len)] = '\0'; \
   21.55 +					} while(0)
   21.56 +
   21.57 +#define string_append(str, s)		string_append_len(str, s, strlen(s))
   21.58 +
   21.59 +#define string_truncate_at(str, s)	do { \
   21.60 +						int _len; \
   21.61 +						_len = (s) - \
   21.62 +						       (char *)(str)->data; \
   21.63 +						*(s) = '\0'; \
   21.64 +						(str)->size = _len + 1; \
   21.65 +					} while(0)
   21.66 +
   21.67 +
   21.68 +static const char *skip_uri_scheme(const char *uri)
   21.69 +{
   21.70 +	/*
   21.71 +	 * RFC 3986 defines scheme as:
   21.72 +	 *	scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
   21.73 +	 */
   21.74 +	if (*uri >= 'a' && *uri <= 'z' || *uri >= 'A' && *uri <= 'Z') {
   21.75 +		do {
   21.76 +		    uri++;
   21.77 +		} while (is_alnum(*uri) || *uri == '+' || *uri == '-' ||
   21.78 +			 *uri == '.');
   21.79 +		if (*uri == ':')
   21.80 +			return uri;
   21.81 +	}
   21.82 +	return NULL;
   21.83 +}
   21.84 +
   21.85 +static char *razor_strndup(const char *s, size_t n)
   21.86 +{
   21.87 +	char *result;
   21.88 +
   21.89 +	if (memchr(s, '\0', n))
   21.90 +		result = strdup(s);
   21.91 +	else {
   21.92 +		result = malloc(n + 1);
   21.93 +		memcpy(result, s, n);
   21.94 +		result[n] = '\0';
   21.95 +	}
   21.96 +
   21.97 +	return result;
   21.98 +}
   21.99 +
  21.100 +#if 0
  21.101 +/*
  21.102 + * Return the (possibly decoded) pchar or 0 on end-of-string or -1 on error
  21.103 + */
  21.104 +static int pchar_get_char_validated(const char *p)
  21.105 +{
  21.106 +	int c;
  21.107 +
  21.108 +	if (p[0]=='\0')
  21.109 +		c = 0;
  21.110 +	else if (p[0]=='%') {
  21.111 +		if (xdigit_value(p[1]) < 0)
  21.112 +			return -1;
  21.113 +		c = xdigit_value(p[1]) * 16;
  21.114 +		if (xdigit_value(p[2]) < 0)
  21.115 +			return -1;
  21.116 +		c += xdigit_value(p[2]);
  21.117 +	} else if (p[0] >= 'a' && p[0] <= 'z' || p[0] >= 'A' && p[0] <= 'Z' || 
  21.118 +		   p[0] >= '0' && p[0] <= '9' ||
  21.119 +		   strchr("-._~!$&'()*+,;=:@", p[0]))
  21.120 +		c = p[0];
  21.121 +	else
  21.122 +		c = -1;
  21.123 +
  21.124 +	return c;
  21.125 +}
  21.126 +#endif
  21.127 +
  21.128 +/*
  21.129 + * Verify the percent encoding. All '%' characters must be followed by
  21.130 + * exactly two hexadecimal digits.
  21.131 + */
  21.132 +static int pct_encoding_validate(const char *s)
  21.133 +{
  21.134 +	while (*s) {
  21.135 +		if (*s == '%') {
  21.136 +			if (xdigit_value(s[1]) < 0 || xdigit_value(s[2]) < 0)
  21.137 +				return -1;
  21.138 +			s += 2;
  21.139 +		}
  21.140 +
  21.141 +		s++;
  21.142 +	}
  21.143 +
  21.144 +	return 0;
  21.145 +}
  21.146 +
  21.147 +static char *pct_encoding_normalize(char *s)
  21.148 +{
  21.149 +	char *retval, *p;
  21.150 +	int c;
  21.151 +
  21.152 +	if (!s)
  21.153 +		return NULL;
  21.154 +
  21.155 +	p = retval = malloc(strlen(s) + 1);
  21.156 +
  21.157 +	while (*s) {
  21.158 +		if (*s == '%') {
  21.159 +			c = pchar_get_char(s);
  21.160 +			if (is_unreserved(c))
  21.161 +				*p++ = c;
  21.162 +			else {
  21.163 +				*p++ = '%';
  21.164 +				*p++ = "0123456789ABCDEF"[c/16];
  21.165 +				*p++ = "0123456789ABCDEF"[c%16];
  21.166 +			}
  21.167 +			pchar_next_char(s);
  21.168 +		} else
  21.169 +			*p++ = *s++;
  21.170 +	}
  21.171 +
  21.172 +	*p++ = '\0';
  21.173 +
  21.174 +	return realloc(retval, p - retval);
  21.175 +}
  21.176 +
  21.177 +static int validate_userinfo(const char *userinfo, struct razor_error **error)
  21.178 +{
  21.179 +	const char *s;
  21.180 +
  21.181 +	for (s = userinfo; *s; s++) {
  21.182 +		if (!is_unreserved(*s) && *s != '%' && !is_sub_delim(*s)
  21.183 +		    && *s != ':') {
  21.184 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.185 +					RAZOR_GENERAL_ERROR_BAD_URI, userinfo,
  21.186 +					"Invalid URI userinfo");
  21.187 +			return -1;
  21.188 +		}
  21.189 +	}
  21.190 +
  21.191 +	return 0;
  21.192 +}
  21.193 +
  21.194 +static int validate_reg_name(const char *reg_name)
  21.195 +{
  21.196 +	const char *s;
  21.197 +
  21.198 +	for (s = reg_name; *s; s++) {
  21.199 +		if (!is_unreserved(*s) && *s != '%' && !is_sub_delim(*s))
  21.200 +			return -1;
  21.201 +	}
  21.202 +
  21.203 +	return 0;
  21.204 +}
  21.205 +
  21.206 +static int validate_ipv4address(const char *s, int length)
  21.207 +{
  21.208 +	int count = 0, digits, octet;
  21.209 +
  21.210 +	for (;;) {
  21.211 +		if (!length)
  21.212 +			return -1;
  21.213 +
  21.214 +		if (*s == '0') {
  21.215 +			digits = 1;
  21.216 +			octet = 0;
  21.217 +		} else {
  21.218 +			if (*s < '1' || *s > '9')
  21.219 +				return -1;
  21.220 +
  21.221 +			octet = *s - '0';
  21.222 +
  21.223 +			for (digits = 1; digits < length; digits++) {
  21.224 +				if (s[digits] >= '0' && s[digits] <= '9') {
  21.225 +					octet *= 10;
  21.226 +					octet += s[digits] - '0';
  21.227 +					if (octet > 255)
  21.228 +						return -1;
  21.229 +				} else
  21.230 +					break;
  21.231 +			}
  21.232 +		}
  21.233 +
  21.234 +		s += digits;
  21.235 +		length -= digits;
  21.236 +
  21.237 +		if (++count == 4)
  21.238 +			break;
  21.239 +
  21.240 +		if (length < 1 || *s != '.')
  21.241 +			return -1;
  21.242 +
  21.243 +		s++;
  21.244 +		length--;
  21.245 +	}
  21.246 +
  21.247 +	return length ? -1 : 0;
  21.248 +}
  21.249 +
  21.250 +static int count_ipv6_pieces(const char **s, int *length)
  21.251 +{
  21.252 +	int count, digits;
  21.253 +
  21.254 +	for (digits = 0; digits < 4 && digits < *length; digits++) {
  21.255 +		if (!is_xdigit((*s)[digits]))
  21.256 +			break;
  21.257 +	}
  21.258 +
  21.259 +	if (!digits)
  21.260 +		return 0;
  21.261 +
  21.262 +	(*s) += digits;
  21.263 +	(*length) -= digits;
  21.264 +	count = 1;
  21.265 +
  21.266 +	if (*length && **s == ':') {
  21.267 +		(*s)++;
  21.268 +		(*length)--;
  21.269 +		count += count_ipv6_pieces(s, length);
  21.270 +		if (count == 1) {
  21.271 +			(*s)--;
  21.272 +			(*length)++;
  21.273 +		}
  21.274 +	}
  21.275 +
  21.276 +	return count;
  21.277 +}
  21.278 +
  21.279 +static int validate_ip_literal(const char *ip_literal, int length)
  21.280 +{
  21.281 +	const char *s, *dot;
  21.282 +	int len, no_pieces, elide;
  21.283 +
  21.284 +	if (length >= 4 && ip_literal[0] == 'v') {
  21.285 +		/* IPvFuture */
  21.286 +		dot = strchr(ip_literal + 2, '.');
  21.287 +		if (!dot || dot >= ip_literal + length)
  21.288 +			return -1;
  21.289 +		for (s = ip_literal + 1; s < dot; s++) {
  21.290 +			if (!is_xdigit(*s))
  21.291 +				return -1;
  21.292 +		}
  21.293 +		for (s = dot + 1; s < ip_literal + length; s++) {
  21.294 +			if (!is_unreserved(*s) && !is_sub_delim(*s) && *s != ':')
  21.295 +				return -1;
  21.296 +		}
  21.297 +	} else {
  21.298 +		/* IPv6address */
  21.299 +		s = ip_literal;
  21.300 +		len = length;
  21.301 +		no_pieces = count_ipv6_pieces(&s, &len);
  21.302 +
  21.303 +		if (len > 1 && s[0] == ':' && s[1] == ':') {
  21.304 +			s += 2;
  21.305 +			len -= 2;
  21.306 +			elide = 1;
  21.307 +			no_pieces += count_ipv6_pieces(&s, &len);
  21.308 +		} else
  21.309 +			elide = 0;
  21.310 +
  21.311 +		if (!validate_ipv4address(s, len))
  21.312 +			no_pieces += 2;
  21.313 +		else if (len)
  21.314 +			return -1;
  21.315 +
  21.316 +		if (no_pieces > 8 || no_pieces == 8 && elide || no_pieces < 1)
  21.317 +			return -1;
  21.318 +	}
  21.319 +
  21.320 +	return 0;
  21.321 +}
  21.322 +
  21.323 +static int validate_host(const char *host, struct razor_error **error)
  21.324 +{
  21.325 +	int retval;
  21.326 +
  21.327 +	if (host[0] == '[' && host[strlen(host) - 1] == ']')
  21.328 +		retval = validate_ip_literal(host + 1, strlen(host) - 2);
  21.329 +	else {
  21.330 +		retval = validate_ipv4address(host, strlen(host));
  21.331 +		if (retval < 0)
  21.332 +			retval = validate_reg_name(host);
  21.333 +	}
  21.334 +
  21.335 +	if (retval)
  21.336 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.337 +				RAZOR_GENERAL_ERROR_BAD_URI, host,
  21.338 +				"Invalid URI host");
  21.339 +
  21.340 +	return retval;
  21.341 +}
  21.342 +
  21.343 +static char *strdown(char *s)
  21.344 +{
  21.345 +	while (*s) {
  21.346 +		if (*s >= 'A' && *s <= 'Z') {
  21.347 +			*s -= 'A';
  21.348 +			*s += 'a';
  21.349 +		}
  21.350 +		s++;
  21.351 +	}
  21.352 +
  21.353 +	return s;
  21.354 +}
  21.355 +
  21.356 +static int razor_uri_parse_authority(struct razor_uri *ru,
  21.357 +				     const char *authority, int length,
  21.358 +				     struct razor_error **error)
  21.359 +{
  21.360 +	const char *s, *auth = authority;
  21.361 +	char *userinfo, *port, *host;
  21.362 +
  21.363 +	s = strchr(auth, '@');
  21.364 +	if (s && s < auth + length) {
  21.365 +		userinfo = razor_strndup(auth, s - auth);
  21.366 +		s++;
  21.367 +		length -= s - auth;
  21.368 +		auth = s;
  21.369 +
  21.370 +		if (validate_userinfo(userinfo, error)) {
  21.371 +			free(userinfo);
  21.372 +			return -1;
  21.373 +		}
  21.374 +	} else
  21.375 +		userinfo = NULL;
  21.376 +
  21.377 +	s = strchr(auth, ':');
  21.378 +	if (s && s < auth + length) {
  21.379 +		s++;
  21.380 +		port = razor_strndup(s, length - (s - auth));
  21.381 +		s--;
  21.382 +		length = s - auth;
  21.383 +
  21.384 +		if (strspn(port, "0123456789") != strlen(port)) {
  21.385 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.386 +					RAZOR_GENERAL_ERROR_BAD_URI, port,
  21.387 +					"Invalid URI port");
  21.388 +			free(userinfo);
  21.389 +			free(port);
  21.390 +			return -1;
  21.391 +		}
  21.392 +	} else
  21.393 +		port = NULL;
  21.394 +
  21.395 +	host = razor_strndup(auth, length);
  21.396 +
  21.397 +	if (validate_host(host, error)) {
  21.398 +		free(userinfo);
  21.399 +		free(port);
  21.400 +		free(host);
  21.401 +		return -1;
  21.402 +	}
  21.403 +
  21.404 +	ru->userinfo = userinfo;
  21.405 +	ru->port = port;
  21.406 +	ru->host = host;
  21.407 +
  21.408 +	return 0;
  21.409 +}
  21.410 +
  21.411 +/*
  21.412 + * Parse either a hier-part or a relative-part
  21.413 + */
  21.414 +static int razor_uri_parse_part(struct razor_uri *ru, const char *part,
  21.415 +				int relative_part, struct razor_error **error)
  21.416 +{
  21.417 +	const char *s, *hp = part;
  21.418 +	char *path, *p;
  21.419 +	int noscheme = 0;
  21.420 +
  21.421 +	if (hp[0] == '/' && hp[1] == '/') {
  21.422 +		hp += 2;
  21.423 +		s = strpbrk(hp, "/?#");
  21.424 +		if (!s)
  21.425 +			s = hp + strlen(hp);
  21.426 +		if (razor_uri_parse_authority(ru, hp, s - hp, error) < 0)
  21.427 +			return -1;
  21.428 +		hp = s;
  21.429 +	} else {
  21.430 +		ru->userinfo = NULL;
  21.431 +		ru->host = NULL;
  21.432 +		ru->port = NULL;
  21.433 +	}
  21.434 +
  21.435 +	if (!*hp) {
  21.436 +		/* path-empty */
  21.437 +		ru->path = strdup("");
  21.438 +		return 0;
  21.439 +	} else if (*hp == '/') {
  21.440 +		/* path-absolute */
  21.441 +		p = path = malloc(strlen(hp) + 1);
  21.442 +		*p++ = '/';
  21.443 +		hp++;
  21.444 +		if (!*hp) {
  21.445 +			*p++ = '\0';
  21.446 +			ru->path = realloc(path, p - path);
  21.447 +			return 0;
  21.448 +		}
  21.449 +	} else if (!ru->host) {
  21.450 +		/* path-rootless or path-noscheme */
  21.451 +		noscheme = relative_part;
  21.452 +		p = path = malloc(strlen(hp) + 1);
  21.453 +	} else {
  21.454 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.455 +				RAZOR_GENERAL_ERROR_BAD_URI, part,
  21.456 +				relative_part ? "Invalid URI relative part" :
  21.457 +				"Invalid URI hierarchical part");
  21.458 +		return -1;
  21.459 +	}
  21.460 +
  21.461 +	if (!is_pchar(*hp) || noscheme && *hp == ':') {
  21.462 +		free(path);
  21.463 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.464 +				RAZOR_GENERAL_ERROR_BAD_URI, part,
  21.465 +				"Invalid character in URI path");
  21.466 +		return -1;
  21.467 +	}
  21.468 +	*p++ = *hp++;
  21.469 +
  21.470 +	while (*hp) {
  21.471 +		if (*hp == '/')
  21.472 +			noscheme = 0;
  21.473 +		else if (!is_pchar(*hp) || noscheme && *hp == ':') {
  21.474 +			free(path);
  21.475 +			razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.476 +					RAZOR_GENERAL_ERROR_BAD_URI, part,
  21.477 +					"Invalid character in URI path");
  21.478 +			return -1;
  21.479 +		}
  21.480 +		*p++ = *hp++;
  21.481 +	}
  21.482 +
  21.483 +	*p++ = '\0';
  21.484 +
  21.485 +	ru->path = realloc(path, p - path);
  21.486 +
  21.487 +	return 0;
  21.488 +}
  21.489 +
  21.490 +void razor_uri_destroy(struct razor_uri *ru)
  21.491 +{
  21.492 +	free(ru->scheme);
  21.493 +	free(ru->userinfo);
  21.494 +	free(ru->host);
  21.495 +	free(ru->port);
  21.496 +	free(ru->path);
  21.497 +	free(ru->query);
  21.498 +	free(ru->fragment);
  21.499 +}
  21.500 +
  21.501 +int razor_uri_parse_uri(struct razor_uri *ru, const char *uri, int absolute,
  21.502 +			struct razor_error **error)
  21.503 +{
  21.504 +	int r;
  21.505 +	const char *s;
  21.506 +	char *hier_part;
  21.507 +
  21.508 +	if (pct_encoding_validate(uri) < 0) {
  21.509 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.510 +				RAZOR_GENERAL_ERROR_BAD_URI, uri,
  21.511 +				"Invalid percent encoding");
  21.512 +		return -1;
  21.513 +	}
  21.514 +
  21.515 +	memset(ru, 0, sizeof(*ru));
  21.516 +
  21.517 +	s = skip_uri_scheme(uri);
  21.518 +	if (!s) {
  21.519 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.520 +				RAZOR_GENERAL_ERROR_BAD_URI, uri,
  21.521 +				"Invalid URI scheme");
  21.522 +		return -1;
  21.523 +	}
  21.524 +	ru->scheme = razor_strndup(uri, s - uri);
  21.525 +	uri = s + 1;
  21.526 +
  21.527 +	s = strchr(uri, '?');
  21.528 +	if (!s)
  21.529 +		s = strchr(uri, '#');
  21.530 +	if (!s)
  21.531 +		s = uri + strlen(uri);
  21.532 +	hier_part = razor_strndup(uri, s - uri);
  21.533 +	uri = s;
  21.534 +
  21.535 +	r = razor_uri_parse_part(ru, hier_part, 0, error);
  21.536 +	free(hier_part);
  21.537 +	if (r) {
  21.538 +		razor_uri_destroy(ru);
  21.539 +		return -1;
  21.540 +	}
  21.541 +
  21.542 +	if (*uri != '?')
  21.543 +		ru->query = NULL;
  21.544 +	else {
  21.545 +		uri++;
  21.546 +		s = strchr(uri, '#');
  21.547 +		if (!s)
  21.548 +			s = uri + strlen(uri);
  21.549 +		ru->query = razor_strndup(uri, s - uri);
  21.550 +		uri = s;
  21.551 +	}
  21.552 +
  21.553 +	if (*uri != '#')
  21.554 +		ru->fragment = NULL;
  21.555 +	else if (absolute) {
  21.556 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.557 +				RAZOR_GENERAL_ERROR_BAD_URI, uri,
  21.558 +				"Fragments are not allowed in absolute URIs");
  21.559 +		razor_uri_destroy(ru);
  21.560 +		return -1;
  21.561 +	} else {
  21.562 +		uri++;
  21.563 +		ru->fragment = strdup(uri);
  21.564 +	}
  21.565 +
  21.566 +	return 0;
  21.567 +}
  21.568 +
  21.569 +int razor_uri_parse_relative_ref(struct razor_uri *ru, const char *uri,
  21.570 +				 struct razor_error **error)
  21.571 +{
  21.572 +	int r;
  21.573 +	const char *s;
  21.574 +	char *relative_part;
  21.575 +
  21.576 +	if (pct_encoding_validate(uri) < 0) {
  21.577 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
  21.578 +				RAZOR_GENERAL_ERROR_BAD_URI, uri,
  21.579 +				"Invalid percent encoding");
  21.580 +		return -1;
  21.581 +	}
  21.582 +
  21.583 +	memset(ru, 0, sizeof(*ru));
  21.584 +
  21.585 +	s = strchr(uri, '?');
  21.586 +	if (!s)
  21.587 +		s = strchr(uri, '#');
  21.588 +	if (!s)
  21.589 +		s = uri + strlen(uri);
  21.590 +	relative_part = razor_strndup(uri, s - uri);
  21.591 +	uri = s;
  21.592 +
  21.593 +	r = razor_uri_parse_part(ru, relative_part, 1, error);
  21.594 +	free(relative_part);
  21.595 +	if (r)
  21.596 +		return -1;
  21.597 +
  21.598 +	if (*uri == '?') {
  21.599 +		uri++;
  21.600 +		s = strchr(uri, '#');
  21.601 +		if (!s)
  21.602 +			s = uri + strlen(uri);
  21.603 +		ru->query = razor_strndup(uri, s - uri);
  21.604 +		uri = s;
  21.605 +	} else
  21.606 +		ru->query = NULL;
  21.607 +
  21.608 +	if (*uri == '#') {
  21.609 +		uri++;
  21.610 +		ru->fragment = strdup(uri);
  21.611 +	} else
  21.612 +		ru->fragment = NULL;
  21.613 +
  21.614 +	return 0;
  21.615 +}
  21.616 +
  21.617 +int razor_uri_parse(struct razor_uri *ru, const char *uri,
  21.618 +		    struct razor_error **error)
  21.619 +{
  21.620 +	struct razor_error *tmp_error = NULL;
  21.621 +	int r;
  21.622 +
  21.623 +	r = razor_uri_parse_uri(ru, uri, 0, &tmp_error);
  21.624 +	if (r < 0) {
  21.625 +		r = razor_uri_parse_relative_ref(ru, uri, NULL);
  21.626 +		if (r < 0)
  21.627 +			razor_propagate_error(error, tmp_error, NULL);
  21.628 +		else
  21.629 +			razor_error_free(tmp_error);
  21.630 +	}
  21.631 +
  21.632 +	return r;
  21.633 +}
  21.634 +
  21.635 +/*
  21.636 + * Following RFC 3986 § 5.2.4
  21.637 + */
  21.638 +static char *remove_dot_segments(const char *path)
  21.639 +{
  21.640 +	struct array output;
  21.641 +	char *input, *in, *s, *t;
  21.642 +	const char *step;
  21.643 +
  21.644 +#ifdef DEBUG
  21.645 +	fprintf(stderr, "STEP   OUTPUT BUFFER         INPUT BUFFER\n");
  21.646 +#endif
  21.647 +
  21.648 +	input = strdup(path);
  21.649 +	in = input;
  21.650 +	string_init(&output);
  21.651 +
  21.652 +#ifdef DEBUG
  21.653 +	fprintf(stderr, " 1 :   %-21s %s\n", string_str(&output), in);
  21.654 +#endif
  21.655 +
  21.656 +	while (*in) {
  21.657 +		if (str_has_prefix(in, "../")) {
  21.658 +			step = "2A";
  21.659 +			in += 3;
  21.660 +		} else if (str_has_prefix(in, "./")) {
  21.661 +			step = "2A";
  21.662 +			in += 2;
  21.663 +		} else if (str_has_prefix(in, "/./")) {
  21.664 +			step = "2B";
  21.665 +			in += 2;
  21.666 +		} else if (!strcmp(in, "/.")) {
  21.667 +			step = "2B";
  21.668 +			in++;
  21.669 +			*in = '/';
  21.670 +		} else if (str_has_prefix(in, "/../")) {
  21.671 +			step = "2C";
  21.672 +			in += 3;
  21.673 +			s = strrchr(string_str(&output), '/');
  21.674 +			if (!s)
  21.675 +				s = string_str(&output);
  21.676 +			string_truncate_at(&output, s);
  21.677 +		} else if (!strcmp(in, "/..")) {
  21.678 +			step = "2C";
  21.679 +			in += 2;
  21.680 +			*in = '/';
  21.681 +			s = strrchr(string_str(&output), '/');
  21.682 +			if (!s)
  21.683 +				s = string_str(&output);
  21.684 +			string_truncate_at(&output, s);
  21.685 +		} else if (!strcmp(in, ".") || !strcmp(in, "..")) {
  21.686 +			step = "2D";
  21.687 +			in += strlen(in);
  21.688 +		} else {
  21.689 +			step = "2E";
  21.690 +			t = strchr(in + 1, '/');
  21.691 +			if (!t)
  21.692 +				t = in + strlen(in);
  21.693 +			string_append_len(&output, in, t - in);
  21.694 +			in = t;
  21.695 +		}
  21.696 +#ifdef DEBUG
  21.697 +		fprintf(stderr, " %s:   %-21s %s\n", step, string_str(&output),
  21.698 +			in);
  21.699 +#endif
  21.700 +	}
  21.701 +
  21.702 +	free(input);
  21.703 +	return string_str(&output);
  21.704 +}
  21.705 +
  21.706 +
  21.707 +/*
  21.708 + * Following RFC 3986 § 6.2.2
  21.709 + */
  21.710 +void razor_uri_normalize(struct razor_uri *ru)
  21.711 +{
  21.712 +	char *s;
  21.713 +
  21.714 +	strdown(ru->scheme);
  21.715 +	if (ru->host)
  21.716 +		strdown(ru->host);
  21.717 +
  21.718 +	s = pct_encoding_normalize(ru->userinfo);
  21.719 +	free(ru->userinfo);
  21.720 +	ru->userinfo = s;
  21.721 +
  21.722 +	s = pct_encoding_normalize(ru->host);
  21.723 +	free(ru->host);
  21.724 +	ru->host = s;
  21.725 +
  21.726 +	s = pct_encoding_normalize(ru->path);
  21.727 +	free(ru->path);
  21.728 +	ru->path = s;
  21.729 +
  21.730 +	s = pct_encoding_normalize(ru->query);
  21.731 +	free(ru->query);
  21.732 +	ru->query = s;
  21.733 +
  21.734 +	s = pct_encoding_normalize(ru->fragment);
  21.735 +	free(ru->fragment);
  21.736 +	ru->fragment = s;
  21.737 +
  21.738 +	s = remove_dot_segments(ru->path);
  21.739 +	free(ru->path);
  21.740 +	ru->path = s;
  21.741 +}
  21.742 +
  21.743 +char *razor_uri_get_authority(const struct razor_uri *ru)
  21.744 +{
  21.745 +	char *result, *r;
  21.746 +	int len = 1;
  21.747 +
  21.748 +	if (ru->host) {
  21.749 +		if (ru->userinfo)
  21.750 +			len += strlen(ru->userinfo) + 1;
  21.751 +		len += strlen(ru->host);
  21.752 +		if (ru->port)
  21.753 +			len += strlen(ru->port) + 1;
  21.754 +	} else
  21.755 +		return NULL;
  21.756 +
  21.757 +	r = result = malloc(len);
  21.758 +
  21.759 +	if (ru->userinfo) {
  21.760 +		strcpy(r, ru->userinfo);
  21.761 +		r += strlen(r);
  21.762 +		*r++ = '@';
  21.763 +	}
  21.764 +
  21.765 +	strcpy(r, ru->host);
  21.766 +	r += strlen(r);
  21.767 +
  21.768 +	if (ru->port) {
  21.769 +		*r++ = ':';
  21.770 +		strcpy(r, ru->port);
  21.771 +	}
  21.772 +
  21.773 +	return result;
  21.774 +}
  21.775 +
  21.776 +/*
  21.777 + * Following RFC 3986 § 5.3
  21.778 + */
  21.779 +char *razor_uri_recompose(const struct razor_uri *ru)
  21.780 +{
  21.781 +	char *authority, *result, *r;
  21.782 +	int len = 1;
  21.783 +
  21.784 +	authority = razor_uri_get_authority(ru);
  21.785 +
  21.786 +	if (ru->scheme)
  21.787 +		len += strlen(ru->scheme) + 1;
  21.788 +	if (authority)
  21.789 +		len += strlen(authority) + 2;
  21.790 +	len += strlen(ru->path);
  21.791 +	if (ru->query)
  21.792 +		len += strlen(ru->query) + 1;
  21.793 +	if (ru->fragment)
  21.794 +		len += strlen(ru->fragment) + 1;
  21.795 +
  21.796 +	r = result = malloc(len);
  21.797 +
  21.798 +	if (ru->scheme) {
  21.799 +		strcpy(r, ru->scheme);
  21.800 +		r += strlen(r);
  21.801 +		*r++ = ':';
  21.802 +	}
  21.803 +
  21.804 +	if (authority) {
  21.805 +		*r++ = '/';
  21.806 +		*r++ = '/';
  21.807 +		strcpy(r, authority);
  21.808 +		free(authority);
  21.809 +		r += strlen(r);
  21.810 +	}
  21.811 +
  21.812 +	strcpy(r, ru->path);
  21.813 +	r += strlen(r);
  21.814 +
  21.815 +	if (ru->query) {
  21.816 +		*r++ = '?';
  21.817 +		strcpy(r, ru->query);
  21.818 +		r += strlen(r);
  21.819 +	}
  21.820 +
  21.821 +	if (ru->fragment) {
  21.822 +		*r++ = '#';
  21.823 +		strcpy(r, ru->fragment);
  21.824 +	}
  21.825 +
  21.826 +	return result;
  21.827 +}
  21.828 +
  21.829 +/*
  21.830 + * Following RFC 3986 § 5.2.3
  21.831 + */
  21.832 +static char *merge_paths(const struct razor_uri *base,const struct razor_uri *R)
  21.833 +{
  21.834 +	char *s, *t, *path;
  21.835 +
  21.836 +	if (base->host && !*base->path)
  21.837 +		path = razor_concat("/", R->path, NULL);
  21.838 +	else {
  21.839 +		s = strrchr(base->path, '/');
  21.840 +		if (s) {
  21.841 +			t = razor_strndup(base->path, s + 1 - base->path);
  21.842 +			path = razor_concat(t, R->path, NULL);
  21.843 +			free(t);
  21.844 +		} else
  21.845 +			path = strdup(R->path);
  21.846 +	}
  21.847 +
  21.848 +	return path;
  21.849 +}
  21.850 +
  21.851 +/*
  21.852 + * Following RFC 3986 § 5.2
  21.853 + */
  21.854 +void razor_uri_resolve(struct razor_uri *T, const struct razor_uri *base,
  21.855 +		       const struct razor_uri *R)
  21.856 +{
  21.857 +	char *s;
  21.858 +
  21.859 +	if (R->scheme) {
  21.860 +		T->scheme = strdup(R->scheme);
  21.861 +		T->userinfo = strdup0(R->userinfo);
  21.862 +		T->host = strdup0(R->host);
  21.863 +		T->port = strdup0(R->port);
  21.864 +		T->path = remove_dot_segments(R->path);
  21.865 +		T->query = strdup0(R->query);
  21.866 +	} else {
  21.867 +		if (R->host) {
  21.868 +			T->userinfo = strdup0(R->userinfo);
  21.869 +			T->host = strdup0(R->host);
  21.870 +			T->port = strdup0(R->port);
  21.871 +			T->path = remove_dot_segments(R->path);
  21.872 +			T->query = strdup0(R->query);
  21.873 +		} else {
  21.874 +			if (!*R->path) {
  21.875 +				T->path = strdup(base->path);
  21.876 +				if (R->query)
  21.877 +					T->query = strdup(R->query);
  21.878 +				else
  21.879 +					T->query = strdup0(base->query);
  21.880 +			} else {
  21.881 +				if (*R->path == '/')
  21.882 +					T->path = remove_dot_segments(R->path);
  21.883 +				else {
  21.884 +					s = merge_paths(base, R);
  21.885 +					T->path = remove_dot_segments(s);
  21.886 +					free(s);
  21.887 +				}
  21.888 +				T->query = strdup0(R->query);
  21.889 +			}
  21.890 +			T->userinfo = strdup0(base->userinfo);
  21.891 +			T->host = strdup0(base->host);
  21.892 +			T->port = strdup0(base->port);
  21.893 +		}
  21.894 +		T->scheme = strdup(base->scheme);
  21.895 +	}
  21.896 +	T->fragment = strdup0(R->fragment);
  21.897 +}
  21.898 +
  21.899 +/*
  21.900 + * This differs from razor_uri_resolve() both in the types of its arguments
  21.901 + * and in the fact that it takes a root URI rather than a base URI. The base
  21.902 + * URI is determined by appending a slash to the root URI (if it doesn't
  21.903 + * already end in a slash). Finally, uri can be explicitly marked as either
  21.904 + * relative (ie., a relative-ref) or not (ie., a URI). This is important as
  21.905 + * otherwise "c:/xxx" could be interpreted as a URI in the "c" scheme.
  21.906 + */
  21.907 +char *razor_resolve_uri_root(const char *root_uri, const char *uri,
  21.908 +			     int is_relative, struct razor_error **error)
  21.909 +{
  21.910 +	int r;
  21.911 +        char *base_uri, *s, *result;
  21.912 +	struct razor_uri ru, base, file;
  21.913 +
  21.914 +	if (!root_uri || !*root_uri)
  21.915 +		root_uri = "file:/";
  21.916 +
  21.917 +	if (root_uri[strlen(root_uri) - 1] == '/')
  21.918 +		base_uri = strdup(root_uri);
  21.919 +	else
  21.920 +		base_uri = razor_concat(root_uri, "/", NULL);
  21.921 +
  21.922 +	r = razor_uri_parse_uri(&base, base_uri, 1, error);
  21.923 +	free(base_uri);
  21.924 +	if (r)
  21.925 +		return NULL;
  21.926 +
  21.927 +	if (is_relative > 0) {
  21.928 +		/*
  21.929 +		 * We can't use razor_uri_parse_relative_ref() to parse
  21.930 +		 * uri in case it starts with a segment that includes a
  21.931 +		 * colon. Thus we use this kludge.
  21.932 +		 */
  21.933 +		s = razor_concat("scheme:", uri, NULL);
  21.934 +		r = razor_uri_parse_uri(&file, s, 0, error);
  21.935 +		free(s);
  21.936 +		if (!r) {
  21.937 +			free(file.scheme);
  21.938 +			file.scheme = NULL;
  21.939 +		}
  21.940 +	}
  21.941 +	else if (!is_relative)
  21.942 +		r = razor_uri_parse_uri(&file, uri, 0, error);
  21.943 +	else
  21.944 +		r = razor_uri_parse(&file, uri, error);
  21.945 +	if (r) {
  21.946 +		razor_uri_destroy(&base);
  21.947 +		return NULL;
  21.948 +	}
  21.949 +
  21.950 +	razor_uri_resolve(&ru, &base, &file);
  21.951 +
  21.952 +	razor_uri_destroy(&base);
  21.953 +	razor_uri_destroy(&file);
  21.954 +
  21.955 +	result = razor_uri_recompose(&ru);
  21.956 +
  21.957 +	razor_uri_destroy(&ru);
  21.958 +
  21.959 +	return result;
  21.960 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/librazor/uri.h	Mon Jul 04 10:48:18 2016 +0100
    22.3 @@ -0,0 +1,50 @@
    22.4 +/*
    22.5 + * Copyright (C) 2016  J. Ali Harlow <ali@juiblex.co.uk>
    22.6 + *
    22.7 + * This program is free software; you can redistribute it and/or modify
    22.8 + * it under the terms of the GNU General Public License as published by
    22.9 + * the Free Software Foundation; either version 2 of the License, or
   22.10 + * (at your option) any later version.
   22.11 + *
   22.12 + * This program is distributed in the hope that it will be useful,
   22.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   22.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22.15 + * GNU General Public License for more details.
   22.16 + *
   22.17 + * You should have received a copy of the GNU General Public License along
   22.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
   22.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   22.20 + */
   22.21 +
   22.22 +#define is_alpha(c)	  ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
   22.23 +
   22.24 +#define is_alnum(c)	  (is_alpha(c) || (c) >= '0' && (c) <= '9')
   22.25 +
   22.26 +#define is_xdigit(c)	  ((c) >= '0' && (c) <= '9' || \
   22.27 +			   (c) >= 'a' && (c) <= 'f' || \
   22.28 +			   (c) >= 'A' && (c) <= 'F')
   22.29 +
   22.30 +#define is_unreserved(c)  (is_alnum(c) || (c) == '-' || (c) == '.' || \
   22.31 +			   (c) == '_' || (c) == '~')
   22.32 +
   22.33 +#define is_sub_delim(c)	  strchr("!$&'()*+,;=", c)
   22.34 +
   22.35 +#define is_pchar(c)	  (is_unreserved(c) || (c) == '%' || \
   22.36 +			   is_sub_delim(c) || (c) == ':' || (c) == '@')
   22.37 +
   22.38 +#define xdigit_value(c)	  ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
   22.39 +			   (c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
   22.40 +			   (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : -1)
   22.41 +
   22.42 +#define pchar_get_char(p) ((p)[0] == '%' ? \
   22.43 +			   xdigit_value((p)[1]) * 16 + xdigit_value((p)[2]) : \
   22.44 +			   (p)[0])
   22.45 +
   22.46 +#define pchar_next_char(p) \
   22.47 +	    do { \
   22.48 +		    if ((p)[0] == '%') \
   22.49 +			    (p) += 3; \
   22.50 +		    else \
   22.51 +			    (p)++; \
   22.52 +	    } while(0)
   22.53 +
    23.1 --- a/librazor/util.c	Sat Jun 11 17:56:48 2016 +0100
    23.2 +++ b/librazor/util.c	Mon Jul 04 10:48:18 2016 +0100
    23.3 @@ -1,7 +1,7 @@
    23.4  /*
    23.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    23.6   * Copyright (C) 2008  Red Hat, Inc
    23.7 - * Copyright (C) 2009, 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
    23.8 + * Copyright (C) 2009, 2011, 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    23.9   *
   23.10   * This program is free software; you can redistribute it and/or modify
   23.11   * it under the terms of the GNU General Public License as published by
   23.12 @@ -22,32 +22,20 @@
   23.13  
   23.14  #include <limits.h>
   23.15  #include <string.h>
   23.16 -#include <sys/types.h>
   23.17 -#include <sys/stat.h>
   23.18  #include <stdlib.h>
   23.19  #include <stdio.h>
   23.20  #include <stdint.h>
   23.21  #include <errno.h>
   23.22  #include <unistd.h>
   23.23 -#include <fcntl.h>
   23.24 -#ifdef MSWIN_API
   23.25 -#include <windows.h>
   23.26 -#include <direct.h>
   23.27 -#else
   23.28 +#ifndef MSWIN_API
   23.29  #include <sys/utsname.h>
   23.30  #endif
   23.31 -#if HAVE_SYS_MMAN_H
   23.32 -#include <sys/mman.h>
   23.33 -#endif
   23.34  #include <assert.h>
   23.35  
   23.36  #include "razor.h"
   23.37 +#include "types/types.h"
   23.38  #include "razor-internal.h"
   23.39  
   23.40 -#ifndef O_BINARY
   23.41 -#define O_BINARY	0
   23.42 -#endif
   23.43 -
   23.44  /* Required by gnulib on non-libc platforms */
   23.45  char *program_name = "librazor";
   23.46  
   23.47 @@ -62,130 +50,6 @@
   23.48  	return p;
   23.49  }
   23.50  
   23.51 -#if HAVE_SYS_MMAN_H
   23.52 -#define OPEN_FILE_USED		(1U<<0)
   23.53 -#define OPEN_FILE_MMAPPED	(1U<<1)
   23.54 -
   23.55 -struct open_file {
   23.56 -	void *addr;
   23.57 -	size_t length;
   23.58 -	uint32_t flags;
   23.59 -};
   23.60 -
   23.61 -struct array open_files = { 0, };
   23.62 -#endif	/* HAVE_SYS_MMAN_H */
   23.63 -
   23.64 -void *
   23.65 -razor_file_get_contents(const char *filename, size_t *length, int private,
   23.66 -			struct razor_error **error)
   23.67 -{
   23.68 -	int fd;
   23.69 -	struct stat st;
   23.70 -	void *addr = NULL;
   23.71 -	size_t nb;
   23.72 -	ssize_t res;
   23.73 -#if HAVE_SYS_MMAN_H
   23.74 -	struct open_file *of, *ofend;
   23.75 -#endif
   23.76 -
   23.77 -	fd = open(filename, O_RDONLY | O_BINARY);
   23.78 -	if (fd < 0) {
   23.79 -		razor_set_error_posix(error, filename);
   23.80 -		return NULL;
   23.81 -	}
   23.82 -
   23.83 -	if (fstat(fd, &st) < 0) {
   23.84 -		razor_set_error_posix(error, filename);
   23.85 -		close(fd);
   23.86 -		return NULL;
   23.87 -	}
   23.88 -
   23.89 -	*length = st.st_size;
   23.90 -
   23.91 -#if HAVE_SYS_MMAN_H
   23.92 -	ofend = open_files.data + open_files.size;
   23.93 -	for (of = open_files.data; of < ofend; of++)
   23.94 -		if (!(of->flags & OPEN_FILE_USED))
   23.95 -			break;
   23.96 -	if (of == ofend) {
   23.97 -		of = array_add(&open_files, sizeof *of);
   23.98 -		of->flags = 0;
   23.99 -	}
  23.100 -
  23.101 -	if (!private) {
  23.102 -		addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  23.103 -		if (addr == MAP_FAILED)
  23.104 -			addr = NULL;
  23.105 -		else
  23.106 -			of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED;
  23.107 -	}
  23.108 -#endif	/* HAVE_SYS_MMAN_H */
  23.109 -	if (!addr) {
  23.110 -		addr = malloc(st.st_size);
  23.111 -		if (addr) {
  23.112 -#if HAVE_SYS_MMAN_H
  23.113 -			of->flags = OPEN_FILE_USED;
  23.114 -#endif
  23.115 -			nb = 0;
  23.116 -			while(nb < st.st_size) {
  23.117 -				res = read(fd, addr + nb, st.st_size - nb);
  23.118 -				if (res <= 0) {
  23.119 -					razor_set_error_posix(error, filename);
  23.120 -					free(addr);
  23.121 -					addr = NULL;
  23.122 -					break;
  23.123 -				}
  23.124 -				nb += res;
  23.125 -			}
  23.126 -		} else
  23.127 -			razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
  23.128 -					"Not enough memory");
  23.129 -	}
  23.130 -	close(fd);
  23.131 -
  23.132 -#if HAVE_SYS_MMAN_H
  23.133 -	of->addr = addr;
  23.134 -	of->length = st.st_size;
  23.135 -#endif
  23.136 -
  23.137 -	return addr;
  23.138 -}
  23.139 -
  23.140 -int razor_file_free_contents(void *addr, size_t length)
  23.141 -{
  23.142 -#if HAVE_SYS_MMAN_H
  23.143 -	int retval, mmapped;
  23.144 -	struct open_file *of, *ofend;
  23.145 -
  23.146 -	ofend = open_files.data + open_files.size;
  23.147 -	for (of = open_files.data; of < ofend; of++)
  23.148 -		if ((of->flags & OPEN_FILE_USED) && of->addr == addr)
  23.149 -			break;
  23.150 -
  23.151 -	if (of == ofend)
  23.152 -		return 1;
  23.153 -
  23.154 -	length = of->length;
  23.155 -	mmapped = of->flags & OPEN_FILE_MMAPPED;
  23.156 -	of->flags &= ~OPEN_FILE_USED;
  23.157 -
  23.158 -	for (of = open_files.data; of < ofend; of++)
  23.159 -		if (of->flags & OPEN_FILE_USED)
  23.160 -			break;
  23.161 -
  23.162 -	if (of == ofend) {
  23.163 -		array_release(&open_files);
  23.164 -		array_init(&open_files);
  23.165 -	}
  23.166 -
  23.167 -	if (mmapped)
  23.168 -		return munmap(addr, length);
  23.169 -#endif
  23.170 -
  23.171 -	free(addr);
  23.172 -	return 0;
  23.173 -}
  23.174 -
  23.175  struct qsort_context {
  23.176  	size_t size;
  23.177  	razor_compare_with_data_func_t compare;
    24.1 --- a/src/import-rpmdb.c	Sat Jun 11 17:56:48 2016 +0100
    24.2 +++ b/src/import-rpmdb.c	Mon Jul 04 10:48:18 2016 +0100
    24.3 @@ -24,6 +24,10 @@
    24.4  #include <string.h>
    24.5  #include <fcntl.h>
    24.6  #include <limits.h>
    24.7 +/*
    24.8 + * Enable rpm 4.4 compatibility mode, see http://rpm.org/wiki/Releases/4.6.0
    24.9 + */
   24.10 +#define _RPM_4_4_COMPAT
   24.11  #include <rpm/rpmlib.h>
   24.12  #include <rpm/rpmdb.h>
   24.13  
    25.1 --- a/src/main.c	Sat Jun 11 17:56:48 2016 +0100
    25.2 +++ b/src/main.c	Mon Jul 04 10:48:18 2016 +0100
    25.3 @@ -1,7 +1,7 @@
    25.4  /*
    25.5   * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    25.6   * Copyright (C) 2008  Red Hat, Inc
    25.7 - * Copyright (C) 2009, 2011-2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
    25.8 + * Copyright (C) 2009, 2011-2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
    25.9   *
   25.10   * This program is free software; you can redistribute it and/or modify
   25.11   * it under the terms of the GNU General Public License as published by
   25.12 @@ -49,7 +49,7 @@
   25.13  
   25.14  static const char system_repo_filename[] = "system.rzdb";
   25.15  static const char next_repo_filename[] = "system-next.rzdb";
   25.16 -static const char rawhide_repo_filename[] = "rawhide.rzdb";
   25.17 +static const char rawhide_repo_uri[] = "file:rawhide.rzdb";
   25.18  static const char *install_root = "";
   25.19  static const char *repo_filename = system_repo_filename;
   25.20  static const char *yum_url;
   25.21 @@ -150,7 +150,7 @@
   25.22  
   25.23  	opterr = 0;
   25.24  
   25.25 -	opt = getopt_long(argc, argv, "+", longopts, NULL);
   25.26 +	opt = getopt_long(argc, (char **)argv, "+", longopts, NULL);
   25.27  
   25.28  	switch (opt)
   25.29  	{
   25.30 @@ -621,13 +621,13 @@
   25.31  	FILE *wfp, *rfp;
   25.32  	char buffer[256], *ptr, *local;
   25.33  	size_t nb, n;
   25.34 +	struct razor_error *error = NULL;
   25.35  
   25.36 -	local = razor_path_from_url(url);
   25.37 +	local = razor_path_from_uri(url, &error);
   25.38  
   25.39  	if (local == NULL) {
   25.40 -		fprintf(stderr,
   25.41 -			"%s: download manually (curl not available)\n",
   25.42 -			file);
   25.43 +		fprintf(stderr, "%s: %s\n", file, razor_error_get_msg(error));
   25.44 +		razor_error_free(error);
   25.45  		return -1;
   25.46  	} else {
   25.47  		rfp = fopen(local, "rb");
   25.48 @@ -723,24 +723,12 @@
   25.49  	curl_easy_setopt(curl, CURLOPT_URL, url);
   25.50  	res = curl_easy_perform(curl);
   25.51  	fclose(fp);
   25.52 +	putc('\n', stderr);
   25.53  	if (res != CURLE_OK) {
   25.54  		fprintf(stderr, "curl error: %s\n", error);
   25.55  		unlink(file);
   25.56  		return -1;
   25.57  	}
   25.58 -	res = curl_easy_getinfo(curl,
   25.59 -				CURLINFO_RESPONSE_CODE, &response);
   25.60 -	if (res != CURLE_OK) {
   25.61 -		fprintf(stderr, "curl error: %s\n", error);
   25.62 -		unlink(file);
   25.63 -		return -1;
   25.64 -	}
   25.65 -	if (response != 200) {
   25.66 -		fprintf(stderr, " - failed %ld\n", response);
   25.67 -		unlink(file);
   25.68 -		return -1;
   25.69 -	}
   25.70 -	fprintf(stderr, "\n");
   25.71  	curl_easy_cleanup(curl);
   25.72  
   25.73  	return 0;
   25.74 @@ -799,13 +787,13 @@
   25.75  	if (set == NULL)
   25.76  		return 1;
   25.77  	atomic = razor_atomic_open("Yum import repository");
   25.78 -	razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL);
   25.79 +	razor_set_write(set, atomic, rawhide_repo_uri, RAZOR_SECTION_ALL);
   25.80  	retval = razor_atomic_commit(atomic);
   25.81  	razor_set_unref(set);
   25.82  	if (retval)
   25.83  		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   25.84  	else
   25.85 -		printf("wrote %s\n", rawhide_repo_filename);
   25.86 +		printf("wrote %s\n", rawhide_repo_uri);
   25.87  	razor_atomic_destroy(atomic);
   25.88  
   25.89  	return retval;
   25.90 @@ -994,7 +982,7 @@
   25.91  
   25.92  	set = razor_root_open_read_only(install_root, &error);
   25.93  	if (set)
   25.94 -		updated = razor_set_open(rawhide_repo_filename, 0, &error);
   25.95 +		updated = razor_set_open(rawhide_repo_uri, 0, &error);
   25.96  	else
   25.97  		updated = NULL;
   25.98  	if (updated == NULL) {
   25.99 @@ -1131,7 +1119,9 @@
  25.100  					  RAZOR_DETAIL_LAST);
  25.101  		
  25.102  		s = rpm_filename(name, version, arch);
  25.103 -		url = razor_concat(yum_url, "/Packages/", s, NULL);
  25.104 +		file = razor_concat("Packages/", s, NULL);
  25.105 +		url = razor_path_relative_to_uri(yum_url, file, NULL);
  25.106 +		free(file);
  25.107  		file = razor_concat("rpms/", s, NULL);
  25.108  		free(s);
  25.109  		if (download_if_missing(url, file) < 0)
  25.110 @@ -1166,7 +1156,7 @@
  25.111  	const char *preunprog, *preun, *postunprog, *postun;
  25.112  	const char *install_prefix;
  25.113  	const char *const *prefixes;
  25.114 -	char *file, *s;
  25.115 +	char *file, *s, *uri, *filename;
  25.116  	uint32_t flags;
  25.117  
  25.118  	importer = razor_importer_create();
  25.119 @@ -1185,14 +1175,20 @@
  25.120  					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
  25.121  					   RAZOR_DETAIL_POSTUN, &postun,
  25.122  					   RAZOR_DETAIL_LAST)) {
  25.123 -		s = rpm_filename(name, version, arch);
  25.124 -		file = razor_concat("rpms/", s, NULL);
  25.125 +		filename = rpm_filename(name, version, arch);
  25.126 +		s = razor_concat("Packages/", filename, NULL);
  25.127 +		uri = razor_path_relative_to_uri(yum_url, s, NULL);
  25.128  		free(s);
  25.129 -		rpm = razor_rpm_open(file, &error);
  25.130 +		file = razor_concat("rpms/", filename, NULL);
  25.131 +		free(filename);
  25.132 +		download_if_missing(uri, file);
  25.133 +		free(uri);
  25.134 +		uri = razor_path_to_uri(file);
  25.135  		free(file);
  25.136 +		rpm = razor_rpm_open(uri, &error);
  25.137 +		free(uri);
  25.138  		if (rpm == NULL) {
  25.139  			razor_atomic_propagate_error(atomic, error, NULL);
  25.140 -			razor_error_free(error);
  25.141  			razor_package_iterator_destroy(pkg_iter);
  25.142  			razor_importer_destroy(importer);
  25.143  			return NULL;
  25.144 @@ -1249,7 +1245,7 @@
  25.145  {
  25.146  	int retval;
  25.147  	const char *name, *version, *arch;
  25.148 -	char *file, *s;
  25.149 +	char *file, *s, *uri;
  25.150  	struct razor_rpm *rpm;
  25.151  	struct razor_error *error=NULL;
  25.152  
  25.153 @@ -1265,12 +1261,13 @@
  25.154  	s = rpm_filename(name, version, arch);
  25.155  	file = razor_concat("rpms/", s, NULL);
  25.156  	free(s);
  25.157 -	rpm = razor_rpm_open(file, &error);
  25.158 +	uri = razor_path_to_uri(file);
  25.159  	free(file);
  25.160 +	rpm = razor_rpm_open(uri, &error);
  25.161 +	free(uri);
  25.162  	if (rpm == NULL) {
  25.163  		razor_atomic_propagate_error(atomic, error, NULL);
  25.164  		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  25.165 -		razor_error_free(error);
  25.166  		return -1;
  25.167  	}
  25.168  	if (relocations)
  25.169 @@ -1441,7 +1438,7 @@
  25.170  		}
  25.171  	} while (opt);
  25.172  
  25.173 -	upstream = razor_set_open(rawhide_repo_filename, 0, &error);
  25.174 +	upstream = razor_set_open(rawhide_repo_uri, 0, &error);
  25.175  	if (upstream == NULL) {
  25.176  		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  25.177  		razor_error_free(error);
  25.178 @@ -1513,7 +1510,7 @@
  25.179  		}
  25.180  	}
  25.181  
  25.182 -	if (razor_atomic_create_dir(atomic, "rpms",
  25.183 +	if (razor_atomic_create_dir(atomic, "file:rpms",
  25.184  				    S_IRWXU | S_IRWXG | S_IRWXO) ||
  25.185  	    razor_atomic_commit(atomic)) {
  25.186  		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  25.187 @@ -1604,7 +1601,7 @@
  25.188  	struct razor_package_iterator *pi;
  25.189  	struct razor_package *package;
  25.190  	const char *pattern, *name, *version, *arch;
  25.191 -	char url[256], file[256];
  25.192 +	char *url, *file, *s, filename[256];
  25.193  	int matches = 0;
  25.194  
  25.195  	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  25.196 @@ -1621,7 +1618,7 @@
  25.197  
  25.198  	pattern = argv[optind];
  25.199  
  25.200 -	set = razor_set_open(rawhide_repo_filename, 0, &error);
  25.201 +	set = razor_set_open(rawhide_repo_uri, 0, &error);
  25.202  	if (set == NULL) {
  25.203  		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  25.204  		razor_error_free(error);
  25.205 @@ -1630,7 +1627,7 @@
  25.206  
  25.207  	atomic = razor_atomic_open("Download packages");
  25.208  
  25.209 -	if (razor_atomic_create_dir(atomic, "rpms", 
  25.210 +	if (razor_atomic_create_dir(atomic, "file:rpms", 
  25.211  				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  25.212  		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  25.213  		razor_atomic_destroy(atomic);
  25.214 @@ -1654,12 +1651,15 @@
  25.215  			continue;
  25.216  
  25.217  		matches++;
  25.218 -		snprintf(url, sizeof url,
  25.219 -			 "%s/Packages/%s-%s.%s.rpm",
  25.220 -			 yum_url, name, version, arch);
  25.221 -		snprintf(file, sizeof file,
  25.222 -			 "rpms/%s-%s.%s.rpm", name, version, arch);
  25.223 +		snprintf(filename, sizeof filename,
  25.224 +			 "%s-%s.%s.rpm", name, version, arch);
  25.225 +		s = razor_concat("Packages/", filename, NULL);
  25.226 +		url = razor_path_relative_to_uri(yum_url, s, NULL);
  25.227 +		free(s);
  25.228 +		file = razor_concat("rpms/", filename, NULL);
  25.229  		download_if_missing(url, file);
  25.230 +		free(url);
  25.231 +		free(file);
  25.232  	}
  25.233  	razor_package_iterator_destroy(pi);
  25.234  	razor_set_unref(set);
  25.235 @@ -1804,7 +1804,7 @@
  25.236  
  25.237  	snprintf(pattern, sizeof pattern, "*%s*", argv[1]);
  25.238  
  25.239 -	set = razor_set_open(rawhide_repo_filename, 0, &error);
  25.240 +	set = razor_set_open(rawhide_repo_uri, 0, &error);
  25.241  	if (set == NULL) {
  25.242  		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  25.243  		razor_error_free(error);
  25.244 @@ -1939,7 +1939,7 @@
  25.245  	while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) {
  25.246  		switch (opt) {
  25.247  			case opt_database:
  25.248 -				razor_set_database_path(optarg);
  25.249 +				razor_set_database_uri(optarg);
  25.250  				break;
  25.251  			case opt_help:
  25.252  			default:
  25.253 @@ -1949,12 +1949,12 @@
  25.254  				printf("  --help              "
  25.255  				       "Show this help message and exit\n");
  25.256  				printf("  --help-commands     List commands\n");
  25.257 -				printf("  --database=PATH     "
  25.258 +				printf("  --database=URI      "
  25.259  				       "Use alternative database\n");
  25.260 -				printf("  --root=ROOT         "
  25.261 -				       "Use ROOT as top level directory\n");
  25.262 -				printf("  --url=URL           "
  25.263 -				       "Use URL as upstream repository\n");
  25.264 +				printf("  --root=URI          "
  25.265 +				       "Use URI as top level directory\n");
  25.266 +				printf("  --url=URI           "
  25.267 +				       "Use URI as upstream repository\n");
  25.268  				return opt != opt_help;
  25.269  			case opt_root:
  25.270  				install_root = optarg;
    26.1 --- a/test/Makefile.am	Sat Jun 11 17:56:48 2016 +0100
    26.2 +++ b/test/Makefile.am	Mon Jul 04 10:48:18 2016 +0100
    26.3 @@ -4,7 +4,7 @@
    26.4  if HAVE_LUA
    26.5    check_SCRIPTS += lua mult-install
    26.6  endif
    26.7 -check_SCRIPTS += order
    26.8 +check_SCRIPTS += order non-ascii relative-root
    26.9  
   26.10  relocate:	relocate.sh primary.xml.gz
   26.11  	cp $(srcdir)/relocate.sh relocate
   26.12 @@ -24,6 +24,12 @@
   26.13  order:	order.sh primary.xml.gz
   26.14  	cp $(srcdir)/order.sh order
   26.15  
   26.16 +non-ascii:	non-ascii.sh primary.xml.gz
   26.17 +	cp $(srcdir)/non-ascii.sh non-ascii
   26.18 +
   26.19 +relative-root:	relative-root.sh primary.xml.gz
   26.20 +	cp $(srcdir)/relative-root.sh relative-root
   26.21 +
   26.22  lua:	lua.sh primary.xml.gz
   26.23  	cp $(srcdir)/lua.sh lua
   26.24  
   26.25 @@ -40,25 +46,26 @@
   26.26  	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh.spec
   26.27  	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh2.spec
   26.28  	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/filesystem.spec
   26.29 -	mkdir -p base/rpms
   26.30 -	mv rpmbuild/RPMS/noarch/*.rpm base/rpms
   26.31 +	rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/aljip.spec
   26.32 +	mkdir -p base/Packages
   26.33 +	mv rpmbuild/RPMS/noarch/*.rpm base/Packages
   26.34  	rm -rf rpmbuild
   26.35 -	createrepo --simple-md-filenames -o base base/rpms
   26.36 +	createrepo --simple-md-filenames base
   26.37  
   26.38  updates/repodata/primary.xml.gz:	zip.spec Makefile
   26.39  	rm -rf rpmbuild updates
   26.40  	mkdir -p rpmbuild/BUILD rpmbuild/RPMS
   26.41  	rpmbuild --define "_topdir `pwd`/rpmbuild" --define "_version 2" \
   26.42  	  -bb $(srcdir)/zip.spec
   26.43 -	mkdir -p updates/rpms
   26.44 -	mv rpmbuild/RPMS/noarch/*.rpm updates/rpms
   26.45 +	mkdir -p updates/Packages
   26.46 +	mv rpmbuild/RPMS/noarch/*.rpm updates/Packages
   26.47  	rm -rf rpmbuild
   26.48 -	createrepo --simple-md-filenames -o updates updates/rpms
   26.49 +	createrepo --simple-md-filenames updates
   26.50  
   26.51  primary.xml.gz:	base/repodata/primary.xml.gz
   26.52  	cp base/repodata/primary.xml.gz base/repodata/filelists.xml.gz .
   26.53  	rm -rf rpms
   26.54 -	ln -s base/rpms .
   26.55 +	ln -s base/Packages rpms
   26.56  
   26.57  TESTS = $(check_SCRIPTS)
   26.58  
   26.59 @@ -68,7 +75,10 @@
   26.60  	zsh.spec		\
   26.61  	zsh2.spec		\
   26.62  	filesystem.spec		\
   26.63 +	aljip.spec		\
   26.64  	order.sh		\
   26.65 +	non-ascii.sh		\
   26.66 +	relative-root.sh	\
   26.67  	mult-install.sh		\
   26.68  	lua.sh			\
   26.69  	remove.sh		\
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/aljip.spec	Mon Jul 04 10:48:18 2016 +0100
    27.3 @@ -0,0 +1,35 @@
    27.4 +%define _source_payload w9.gzdio
    27.5 +%define _binary_payload w9.gzdio
    27.6 +
    27.7 +Name:      aljip
    27.8 +Summary:   Test package
    27.9 +Group:     Test
   27.10 +License:   GPL
   27.11 +Version:   %{_version}
   27.12 +Release:   1
   27.13 +Source:    aljip.tar
   27.14 +BuildArch: noarch
   27.15 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
   27.16 +Prefix:    /usr
   27.17 +
   27.18 +%description
   27.19 +Test package
   27.20 +
   27.21 +%prep
   27.22 +
   27.23 +%build
   27.24 +
   27.25 +%install
   27.26 +mkdir -p $RPM_BUILD_ROOT/usr/bin
   27.27 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/data file.alz"
   27.28 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/-._~.alz"
   27.29 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/!$&'()*+,;=.alz"
   27.30 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/:?#[]@.alz"
   27.31 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/sébastien.alz"
   27.32 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/lukáš.alz"
   27.33 +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/알집.sh"
   27.34 +
   27.35 +%clean
   27.36 +
   27.37 +%files
   27.38 +/usr/bin/*
    28.1 --- a/test/details.sh	Sat Jun 11 17:56:48 2016 +0100
    28.2 +++ b/test/details.sh	Mon Jul 04 10:48:18 2016 +0100
    28.3 @@ -4,11 +4,12 @@
    28.4  else
    28.5      razor=../src/razor
    28.6  fi
    28.7 -export RAZOR_ROOT=`mktemp -dt` || exit 1
    28.8 +tmpdir=`mktemp -dt` || exit 1
    28.9 +export RAZOR_ROOT="file:$tmpdir"
   28.10  $razor init || exit 1
   28.11 -export YUM_URL="file://localhost/`pwd`"
   28.12 +export YUM_URL="file:`pwd`/base"
   28.13  $razor import-yum || exit 1
   28.14  $razor install zsh2 || exit 1
   28.15  $razor info zsh2 > details.out || exit 1
   28.16  diff -u $srcdir/details.ref details.out || exit 1
   28.17 -rm -rf "$RAZOR_ROOT"
   28.18 +rm -rf "$tmpdir"
    29.1 --- a/test/lua.sh	Sat Jun 11 17:56:48 2016 +0100
    29.2 +++ b/test/lua.sh	Mon Jul 04 10:48:18 2016 +0100
    29.3 @@ -6,23 +6,24 @@
    29.4  fi
    29.5  check_filesystem()
    29.6  {
    29.7 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    29.8 +    if [ ! -e "$tmpdir$1" ]; then 
    29.9  	echo $1: Not in filesystem >&2
   29.10  	exit 1
   29.11      fi
   29.12  }
   29.13  check_file()
   29.14  {
   29.15 -    ../src/razor list-files | grep -x "$1" > /dev/null
   29.16 +    ../src/razor list-files | grep -F -x "$1" > /dev/null
   29.17      if [ $? -ne 0 ]; then
   29.18  	echo $1: Not in database >&2
   29.19  	exit 1
   29.20      fi
   29.21      check_filesystem "$1"
   29.22  }
   29.23 -export RAZOR_ROOT=`mktemp -dt` || exit 1
   29.24 +tmpdir=`mktemp -dt` || exit 1
   29.25 +export RAZOR_ROOT="file:$tmpdir"
   29.26  $razor init || exit 1
   29.27 -export YUM_URL="file://localhost/`pwd`"
   29.28 +export YUM_URL="file:`pwd`/base"
   29.29  $razor import-yum || exit 1
   29.30  $razor install filesystem || exit 1
   29.31  check_file /etc
   29.32 @@ -30,4 +31,4 @@
   29.33  check_file /usr/lib
   29.34  check_file /usr/include
   29.35  check_filesystem /media/cdrom
   29.36 -rm -rf "$RAZOR_ROOT"
   29.37 +rm -rf "$tmpdir"
    30.1 --- a/test/mult-install.sh	Sat Jun 11 17:56:48 2016 +0100
    30.2 +++ b/test/mult-install.sh	Mon Jul 04 10:48:18 2016 +0100
    30.3 @@ -6,37 +6,37 @@
    30.4  fi
    30.5  fs_check_file()
    30.6  {
    30.7 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    30.8 +    if [ ! -e "$tmpdir$1" ]; then 
    30.9  	echo $1: Not in filesystem >&2
   30.10 -	ls -R "$RAZOR_ROOT" >&2
   30.11 +	ls -R "$tmpdir" >&2
   30.12  	exit 1
   30.13      fi
   30.14  }
   30.15  fs_check_file_contents()
   30.16  {
   30.17      fs_check_file "$1"
   30.18 -    if [ `cat "$RAZOR_ROOT$1"` != "$2" ]; then
   30.19 +    if [ `cat "$tmpdir$1"` != "$2" ]; then
   30.20  	echo $1: Unexpected contents >&2
   30.21 -	cat "$RAZOR_ROOT$1" >&2
   30.22 +	cat "$tmpdir$1" >&2
   30.23  	exit 1
   30.24      fi
   30.25  }
   30.26  fs_check_no_file()
   30.27  {
   30.28 -    if [ -e "$RAZOR_ROOT$1" ]; then 
   30.29 +    if [ -e "$tmpdir$1" ]; then 
   30.30  	echo $1: Still in filesystem >&2
   30.31  	exit 1
   30.32      fi
   30.33  }
   30.34  check_file()
   30.35  {
   30.36 -    $razor list-files | grep -x "$1" > /dev/null
   30.37 +    $razor list-files | grep -F -x "$1" > /dev/null
   30.38      if [ $? -ne 0 ]; then
   30.39  	echo $1: Not in database >&2
   30.40  	$razor list-files >&2
   30.41  	exit 1
   30.42      fi
   30.43 -    $razor list-files "$1" | grep -x "$1" > /dev/null
   30.44 +    $razor list-files "$1" | grep -F -x "$1" > /dev/null
   30.45      if [ $? -ne 0 ]; then
   30.46  	echo $1: Not seen by patterned list >&2
   30.47  	$razor list-files "$1" >&2
   30.48 @@ -50,7 +50,7 @@
   30.49      fi
   30.50      for nevra in "$pkgs"; do
   30.51  	name=`echo $nevra | sed 's/\-.*$//'`
   30.52 -	$razor list-package-files "$name" | grep -x "$1" > /dev/null
   30.53 +	$razor list-package-files "$name" | grep -F -x "$1" > /dev/null
   30.54  	if [ $? -ne 0 ]; then
   30.55  	    echo $1: Not in database for package $name >&2
   30.56  	    $razor list-package-files "$name"
   30.57 @@ -61,7 +61,7 @@
   30.58  }
   30.59  check_no_file()
   30.60  {
   30.61 -    $razor list-files | grep -x "$1" > /dev/null
   30.62 +    $razor list-files | grep -F -x "$1" > /dev/null
   30.63      if [ $? -eq 0 ]; then
   30.64  	echo $1: Still in database >&2
   30.65  	exit 1
   30.66 @@ -76,9 +76,10 @@
   30.67  	exit 1
   30.68      fi
   30.69  }
   30.70 -export RAZOR_ROOT=`mktemp -dt` || exit 1
   30.71 +tmpdir=`mktemp -dt` || exit 1
   30.72 +export RAZOR_ROOT="file:$tmpdir"
   30.73  $razor init || exit 1
   30.74 -export YUM_URL="file://localhost/`pwd`"
   30.75 +export YUM_URL="file:`pwd`/base"
   30.76  $razor import-yum || exit 1
   30.77  $razor install --relocate /usr=/opt zip || exit 1
   30.78  fs_check_file_contents /opt/bin/zip zip-1-1
   30.79 @@ -87,4 +88,4 @@
   30.80  check_install_count zip 2
   30.81  $razor install --relocate /usr=/opt zip || exit 1
   30.82  check_install_count zip 3
   30.83 -rm -rf "$RAZOR_ROOT"
   30.84 +rm -rf "$tmpdir"
    31.1 --- a/test/named-root.sh	Sat Jun 11 17:56:48 2016 +0100
    31.2 +++ b/test/named-root.sh	Mon Jul 04 10:48:18 2016 +0100
    31.3 @@ -6,19 +6,19 @@
    31.4  fi
    31.5  check_file()
    31.6  {
    31.7 -    $razor list-files | grep -x "$1" > /dev/null
    31.8 +    $razor list-files | grep -F -x "$1" > /dev/null
    31.9      if [ $? -ne 0 ]; then
   31.10  	echo $1: Not in database >&2
   31.11  	$razor list-files >&2
   31.12  	exit 1
   31.13      fi
   31.14 -    $razor list-files c: | grep -x "$1" > /dev/null
   31.15 +    $razor list-files c: | grep -F -x "$1" > /dev/null
   31.16      if [ $? -ne 0 ]; then
   31.17  	echo $1: Not seen by named root list >&2
   31.18  	$razor list-files c: >&2
   31.19  	exit 1
   31.20      fi
   31.21 -    $razor list-files "$1" | grep -x "$1" > /dev/null
   31.22 +    $razor list-files "$1" | grep -F -x "$1" > /dev/null
   31.23      if [ $? -ne 0 ]; then
   31.24  	echo $1: Not seen by patterned list >&2
   31.25  	$razor list-files "$1" >&2
   31.26 @@ -32,24 +32,23 @@
   31.27      fi
   31.28      for nevra in "$pkgs"; do
   31.29  	name=`echo $nevra | sed 's/\-.*$//'`
   31.30 -	$razor list-package-files "$name" | grep -x "$1" > /dev/null
   31.31 +	$razor list-package-files "$name" | grep -F -x "$1" > /dev/null
   31.32  	if [ $? -ne 0 ]; then
   31.33  	    echo $1: Not in database for package $name >&2
   31.34  	    $razor list-package-files "$name"
   31.35  	    exit 1
   31.36  	fi
   31.37      done
   31.38 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
   31.39 +    if [ ! -e "$tmpdir/$1" ]; then 
   31.40  	echo $1: Not in filesystem >&2
   31.41  	exit 1
   31.42      fi
   31.43  }
   31.44  tmpdir=`mktemp -dt` || exit 1
   31.45 -export RAZOR_ROOT="$tmpdir/x-"
   31.46 -mkdir -p "$tmpdir/x-/var/lib" "$tmpdir/x-c:"
   31.47 +export RAZOR_ROOT="file:$tmpdir"
   31.48  export RAZOR_NO_ROOT_NAME_CHECKS=1
   31.49  $razor init || exit 1
   31.50 -export YUM_URL="file://localhost/`pwd`"
   31.51 +export YUM_URL="file:`pwd`/base"
   31.52  $razor import-yum || exit 1
   31.53  $razor install --relocate /usr=c:/test zap || exit 1
   31.54  $razor install --relocate /usr=c:/test zip || exit 1
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/test/non-ascii.sh	Mon Jul 04 10:48:18 2016 +0100
    32.3 @@ -0,0 +1,34 @@
    32.4 +#!/bin/sh
    32.5 +if [ $# -gt 0 ]; then
    32.6 +    razor="$1"
    32.7 +else
    32.8 +    razor=../src/razor
    32.9 +fi
   32.10 +check_file()
   32.11 +{
   32.12 +    $razor list-files | grep -F -x "$1" > /dev/null
   32.13 +    if [ $? -ne 0 ]; then
   32.14 +	echo $1: Not in database >&2
   32.15 +	$razor list-files >&2
   32.16 +	exit 1
   32.17 +    fi
   32.18 +    if [ ! -e "$tmpdir$1" ]; then 
   32.19 +	echo $1: Not in filesystem >&2
   32.20 +	ls -R "$tmpdir" >&2
   32.21 +	exit 1
   32.22 +    fi
   32.23 +}
   32.24 +tmpdir=`mktemp -dt` || exit 1
   32.25 +export RAZOR_ROOT="file:$tmpdir"
   32.26 +$razor init || exit 1
   32.27 +export YUM_URL="file:`pwd`/base"
   32.28 +$razor import-yum || exit 1
   32.29 +$razor install aljip || exit 1
   32.30 +check_file "/usr/bin/data file.alz"
   32.31 +check_file "/usr/bin/-._~.alz"
   32.32 +check_file "/usr/bin/!$&'()*+,;=.alz"
   32.33 +check_file "/usr/bin/:?#[]@.alz"
   32.34 +check_file "/usr/bin/sébastien.alz"
   32.35 +check_file "/usr/bin/lukáš.alz"
   32.36 +check_file "/usr/bin/알집.sh"
   32.37 +rm -rf "$tmpdir"
    33.1 --- a/test/order.sh	Sat Jun 11 17:56:48 2016 +0100
    33.2 +++ b/test/order.sh	Mon Jul 04 10:48:18 2016 +0100
    33.3 @@ -6,16 +6,17 @@
    33.4  fi
    33.5  check_file()
    33.6  {
    33.7 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    33.8 +    if [ ! -e "$tmpdir$1" ]; then 
    33.9  	echo $1: Not in filesystem >&2
   33.10  	exit 1
   33.11      fi
   33.12  }
   33.13 -export RAZOR_ROOT=`mktemp -dt` || exit 1
   33.14 +tmpdir=`mktemp -dt` || exit 1
   33.15 +export RAZOR_ROOT="file:$tmpdir"
   33.16  $razor init || exit 1
   33.17 -export YUM_URL="file://localhost/`pwd`"
   33.18 +export YUM_URL="file:`pwd`/base"
   33.19  $razor import-yum || exit 1
   33.20  $razor install zip zsh || exit 1
   33.21  check_file /usr/var/lib/zip/data.zap
   33.22  check_file /usr/var/lib/zsh/data.zip
   33.23 -rm -rf "$RAZOR_ROOT"
   33.24 +rm -rf "$tmpdir"
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/test/relative-root.sh	Mon Jul 04 10:48:18 2016 +0100
    34.3 @@ -0,0 +1,32 @@
    34.4 +#!/bin/sh
    34.5 +if [ $# -gt 0 ]; then
    34.6 +    razor="$1"
    34.7 +else
    34.8 +    razor=`pwd`/../src/razor
    34.9 +fi
   34.10 +check_file()
   34.11 +{
   34.12 +    (cd /tmp; $razor list-files) | grep -F -x "$1" > /dev/null
   34.13 +    if [ $? -ne 0 ]; then
   34.14 +	echo $1: Not in database >&2
   34.15 +	(cd /tmp; $razor list-files) >&2
   34.16 +	exit 1
   34.17 +    fi
   34.18 +    if [ ! -e "$tmpdir$1" ]; then 
   34.19 +	echo $1: Not in filesystem >&2
   34.20 +	ls -R "$tmpdir" >&2
   34.21 +	exit 1
   34.22 +    fi
   34.23 +}
   34.24 +tmpdir=`mktemp --directory --tmpdir=/tmp` || exit 1
   34.25 +export RAZOR_ROOT="`echo $tmpdir | sed -e 's&/tmp/&file:&'`"
   34.26 +(cd /tmp; $razor init) || exit 1
   34.27 +export YUM_URL="file:`pwd`/base"
   34.28 +(cd /tmp; $razor import-yum) || exit 1
   34.29 +(cd /tmp; $razor install zap) || exit 1
   34.30 +(cd /tmp; $razor install --relocate /usr=/opt --relocate /etc=/opt/etc zsh) || exit 1
   34.31 +check_file /etc/zsh.conf
   34.32 +check_file /usr/bin/zap
   34.33 +check_file /opt/bin/zip
   34.34 +check_file /opt/bin/zsh
   34.35 +rm -rf "$tmpdir"
    35.1 --- a/test/relocate.sh	Sat Jun 11 17:56:48 2016 +0100
    35.2 +++ b/test/relocate.sh	Mon Jul 04 10:48:18 2016 +0100
    35.3 @@ -1,4 +1,5 @@
    35.4  #!/bin/sh
    35.5 +set -x
    35.6  if [ $# -gt 0 ]; then
    35.7      razor="$1"
    35.8  else
    35.9 @@ -6,19 +7,20 @@
   35.10  fi
   35.11  check_file()
   35.12  {
   35.13 -    $razor list-files | grep -x "$1" > /dev/null
   35.14 +    $razor list-files | grep -F -x "$1" > /dev/null
   35.15      if [ $? -ne 0 ]; then
   35.16  	echo $1: Not in database >&2
   35.17  	exit 1
   35.18      fi
   35.19 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
   35.20 +    if [ ! -e "$tmpdir$1" ]; then 
   35.21  	echo $1: Not in filesystem >&2
   35.22  	exit 1
   35.23      fi
   35.24  }
   35.25 -export RAZOR_ROOT=`mktemp -dt` || exit 1
   35.26 +tmpdir=`mktemp -dt` || exit 1
   35.27 +export RAZOR_ROOT="file:$tmpdir"
   35.28  $razor init || exit 1
   35.29 -export YUM_URL="file://localhost/`pwd`"
   35.30 +export YUM_URL="file:`pwd`/base"
   35.31  $razor import-yum || exit 1
   35.32  $razor install zap || exit 1
   35.33  $razor install --relocate /usr=/opt --relocate /etc=/opt/etc zsh || exit 1
   35.34 @@ -26,4 +28,4 @@
   35.35  check_file /usr/bin/zap
   35.36  check_file /opt/bin/zip
   35.37  check_file /opt/bin/zsh
   35.38 -rm -rf "$RAZOR_ROOT"
   35.39 +rm -rf "$tmpdir"
    36.1 --- a/test/remove.sh	Sat Jun 11 17:56:48 2016 +0100
    36.2 +++ b/test/remove.sh	Mon Jul 04 10:48:18 2016 +0100
    36.3 @@ -6,28 +6,28 @@
    36.4  fi
    36.5  fs_check_file()
    36.6  {
    36.7 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    36.8 +    if [ ! -e "$tmpdir$1" ]; then 
    36.9  	echo $1: Not in filesystem >&2
   36.10 -	ls -R "$RAZOR_ROOT" >&2
   36.11 +	ls -R "$tmpdir" >&2
   36.12  	exit 1
   36.13      fi
   36.14  }
   36.15  fs_check_no_file()
   36.16  {
   36.17 -    if [ -e "$RAZOR_ROOT$1" ]; then 
   36.18 +    if [ -e "$tmpdir$1" ]; then 
   36.19  	echo $1: Still in filesystem >&2
   36.20  	exit 1
   36.21      fi
   36.22  }
   36.23  check_file()
   36.24  {
   36.25 -    $razor list-files | grep -x "$1" > /dev/null
   36.26 +    $razor list-files | grep -F -x "$1" > /dev/null
   36.27      if [ $? -ne 0 ]; then
   36.28  	echo $1: Not in database >&2
   36.29  	$razor list-files >&2
   36.30  	exit 1
   36.31      fi
   36.32 -    $razor list-files "$1" | grep -x "$1" > /dev/null
   36.33 +    $razor list-files "$1" | grep -F -x "$1" > /dev/null
   36.34      if [ $? -ne 0 ]; then
   36.35  	echo $1: Not seen by patterned list >&2
   36.36  	$razor list-files "$1" >&2
   36.37 @@ -41,7 +41,7 @@
   36.38      fi
   36.39      for nevra in "$pkgs"; do
   36.40  	name=`echo $nevra | sed 's/\-.*$//'`
   36.41 -	$razor list-package-files "$name" | grep -x "$1" > /dev/null
   36.42 +	$razor list-package-files "$name" | grep -F -x "$1" > /dev/null
   36.43  	if [ $? -ne 0 ]; then
   36.44  	    echo $1: Not in database for package $name >&2
   36.45  	    $razor list-package-files "$name"
   36.46 @@ -52,16 +52,17 @@
   36.47  }
   36.48  check_no_file()
   36.49  {
   36.50 -    $razor list-files | grep -x "$1" > /dev/null
   36.51 +    $razor list-files | grep -F -x "$1" > /dev/null
   36.52      if [ $? -eq 0 ]; then
   36.53  	echo $1: Still in database >&2
   36.54  	exit 1
   36.55      fi
   36.56      fs_check_no_file $1
   36.57  }
   36.58 -export RAZOR_ROOT=`mktemp -dt` || exit 1
   36.59 +tmpdir=`mktemp -dt` || exit 1
   36.60 +export RAZOR_ROOT="file:$tmpdir"
   36.61  $razor init || exit 1
   36.62 -export YUM_URL="file://localhost/`pwd`"
   36.63 +export YUM_URL="file:`pwd`/base"
   36.64  $razor import-yum || exit 1
   36.65  $razor install --relocate /usr=/opt zip || exit 1
   36.66  fs_check_file /opt/var/lib/zip/data.zap
   36.67 @@ -81,4 +82,4 @@
   36.68  fs_check_file /opt/var/lib/zip/data.zap
   36.69  $razor remove zsh2 zip || exit 1
   36.70  fs_check_no_file /opt/var/lib/zip/data.zap
   36.71 -rm -rf "$RAZOR_ROOT"
   36.72 +rm -rf "$tmpdir"
    37.1 --- a/test/update.sh	Sat Jun 11 17:56:48 2016 +0100
    37.2 +++ b/test/update.sh	Mon Jul 04 10:48:18 2016 +0100
    37.3 @@ -6,37 +6,37 @@
    37.4  fi
    37.5  fs_check_file()
    37.6  {
    37.7 -    if [ ! -e "$RAZOR_ROOT$1" ]; then 
    37.8 +    if [ ! -e "$tmpdir$1" ]; then 
    37.9  	echo $1: Not in filesystem >&2
   37.10 -	ls -R "$RAZOR_ROOT" >&2
   37.11 +	ls -R "$tmpdir" >&2
   37.12  	exit 1
   37.13      fi
   37.14  }
   37.15  fs_check_file_contents()
   37.16  {
   37.17      fs_check_file "$1"
   37.18 -    if [ `cat "$RAZOR_ROOT$1"` != "$2" ]; then
   37.19 +    if [ `cat "$tmpdir$1"` != "$2" ]; then
   37.20  	echo $1: Unexpected contents >&2
   37.21 -	cat "$RAZOR_ROOT$1" >&2
   37.22 +	cat "$tmpdir$1" >&2
   37.23  	exit 1
   37.24      fi
   37.25  }
   37.26  fs_check_no_file()
   37.27  {
   37.28 -    if [ -e "$RAZOR_ROOT$1" ]; then 
   37.29 +    if [ -e "$tmpdir$1" ]; then 
   37.30  	echo $1: Still in filesystem >&2
   37.31  	exit 1
   37.32      fi
   37.33  }
   37.34  check_file()
   37.35  {
   37.36 -    $razor list-files | grep -x "$1" > /dev/null
   37.37 +    $razor list-files | grep -F -x "$1" > /dev/null
   37.38      if [ $? -ne 0 ]; then
   37.39  	echo $1: Not in database >&2
   37.40  	$razor list-files >&2
   37.41  	exit 1
   37.42      fi
   37.43 -    $razor list-files "$1" | grep -x "$1" > /dev/null
   37.44 +    $razor list-files "$1" | grep -F -x "$1" > /dev/null
   37.45      if [ $? -ne 0 ]; then
   37.46  	echo $1: Not seen by patterned list >&2
   37.47  	$razor list-files "$1" >&2
   37.48 @@ -50,7 +50,7 @@
   37.49      fi
   37.50      for nevra in "$pkgs"; do
   37.51  	name=`echo $nevra | sed 's/\-.*$//'`
   37.52 -	$razor list-package-files "$name" | grep -x "$1" > /dev/null
   37.53 +	$razor list-package-files "$name" | grep -F -x "$1" > /dev/null
   37.54  	if [ $? -ne 0 ]; then
   37.55  	    echo $1: Not in database for package $name >&2
   37.56  	    $razor list-package-files "$name"
   37.57 @@ -61,7 +61,7 @@
   37.58  }
   37.59  check_no_file()
   37.60  {
   37.61 -    $razor list-files | grep -x "$1" > /dev/null
   37.62 +    $razor list-files | grep -F -x "$1" > /dev/null
   37.63      if [ $? -eq 0 ]; then
   37.64  	echo $1: Still in database >&2
   37.65  	exit 1
   37.66 @@ -78,13 +78,14 @@
   37.67  }
   37.68  set_repository()
   37.69  {
   37.70 +    export YUM_URL="file:`pwd`/$1"
   37.71      cp $1/repodata/primary.xml.gz $1/repodata/filelists.xml.gz .
   37.72      rm -rf rpms
   37.73 -    ln -s $1/rpms .
   37.74 +    ln -s $1/Packages rpms
   37.75  }
   37.76 -export RAZOR_ROOT=`mktemp -dt` || exit 1
   37.77 +tmpdir=`mktemp -dt` || exit 1
   37.78 +export RAZOR_ROOT="file:$tmpdir"
   37.79  $razor init || exit 1
   37.80 -export YUM_URL="file://localhost/`pwd`"
   37.81  set_repository base
   37.82  $razor import-yum || exit 1
   37.83  $razor install --relocate /usr=/opt zip || exit 1
   37.84 @@ -118,4 +119,4 @@
   37.85  $razor install --relocate /usr=/opt zip || exit 1
   37.86  $razor update --relocate /usr=/opt zip || exit 1
   37.87  check_install_count zip 1
   37.88 -rm -rf "$RAZOR_ROOT"
   37.89 +rm -rf "$tmpdir"