# HG changeset patch # User J. Ali Harlow # Date 1467625698 -3600 # Node ID 008c75a5e08d8194c79b46d33811cd2d8b003de4 # Parent 7442b30ecaaeeb8d190f3d2b33fab3a978de8565 Switch to a URI-based API diff -r 7442b30ecaae -r 008c75a5e08d librazor/Makefile.am --- a/librazor/Makefile.am Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/Makefile.am Mon Jul 04 10:48:18 2016 +0100 @@ -14,7 +14,7 @@ -DPACKAGE_LIB_DIR=\""$(libdir)"\" lib_LTLIBRARIES = librazor.la -check_PROGRAMS = test-pfu +check_PROGRAMS = test-pfu test-uri if HAVE_LUA check_PROGRAMS += test-lua endif @@ -30,11 +30,14 @@ librazor_la_SOURCES = \ razor-internal.h \ + uri.h \ razor.h \ razor.c \ root.c \ dump.c \ util.c \ + uri-io.c \ + uri.c \ path.c \ rpm.c \ iterator.c \ @@ -58,15 +61,22 @@ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) test_pfu_SOURCES = test-pfu.c -test_pfu_LDADD = path.lo util.lo error.lo types/libtypes.la \ +test_pfu_LDADD = path.lo uri.lo util.lo error.lo types/libtypes.la \ ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS) TESTS = test-pfu +test_uri_SOURCES = test-uri.c +test_uri_CFLAGS = $(AM_CFLAGS) +test_uri_LDADD = uri.lo util.lo path.lo error.lo types/libtypes.la \ + $(LUA_LIBS) ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS) + +TESTS += test-uri + if HAVE_LUA test_lua_SOURCES = test-lua.c - test_lua_LDADD = lua.lo util.lo error.lo types/libtypes.la $(LUA_LIBS) \ - ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS) + test_lua_LDADD = lua.lo uri.lo uri-io.lo util.lo path.lo error.lo \ + types/libtypes.la $(LUA_LIBS) ../gl/libgnu.la $(INTLLIBS) $(EXTRA_LIBS) TESTS += test-lua endif diff -r 7442b30ecaae -r 008c75a5e08d librazor/atomic-actions.c --- a/librazor/atomic-actions.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/atomic-actions.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 J. Ali Harlow + * Copyright (C) 2012, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,9 +25,6 @@ #include #include #include -#include -#include -#include #include #include "razor-internal.h" @@ -87,7 +84,7 @@ while(action) { a = atomic_action_list_pop_head(&action); - free(a->args.path); + free(a->args.uri); switch(a->type) { case ACTION_MAKE_DIRS: @@ -166,13 +163,11 @@ strcpy(buffer, action->args.u.make_dirs.root); p = buffer + strlen(buffer); - slash = action->args.path; + slash = action->args.uri; + if (p > buffer && p[-1] != ':' && p[-1] != '/' && *slash != '/') + *p++ = '/'; for (; *slash != '\0'; slash = next) { -#ifdef MSWIN_API - next = strpbrk(slash + 1, "/\\"); -#else next = strchr(slash + 1, '/'); -#endif if (next == NULL) break; @@ -184,7 +179,7 @@ continue; prim = atomic_action_new(ACTION_CREATE_DIR); - prim->args.path = strdup(buffer); + prim->args.uri = strdup(buffer); prim->args.u.create_dir.mode = S_IRWXU | S_IRWXG | S_IRWXO; primitives = atomic_action_list_prepend(primitives, prim); } @@ -198,12 +193,8 @@ static struct atomic_action * atomic_action_remove(struct razor_atomic *atomic, struct atomic_action *action) { -#ifdef MSWIN_API - wchar_t *path; - _WDIR *dir; -#else - DIR *dir; -#endif + void *dir; + char *name; struct atomic_action *prim; if (razor_atomic_in_error_state(atomic)) { @@ -214,27 +205,20 @@ /* * Non-empty directories should NOT be removed */ -#ifdef MSWIN_API - path = razor_utf8_to_utf16(action->args.path, -1); - - dir = _wopendir(path); - if (dir && _wreaddir(dir)) { - atomic_action_free(action); - action = NULL; + dir = razor_uri_opendir(action->args.uri, NULL); + if (dir) { + name = razor_uri_readdir(dir, NULL); + razor_uri_closedir(dir, NULL); + if (name) { + free(name); + atomic_action_free(action); + action = NULL; + } } - _wclosedir(dir); -#else - dir = opendir(action->args.path); - if (dir && readdir(dir)) { - atomic_action_free(action); - action = NULL; - } - closedir(dir); -#endif if (action) { prim = atomic_action_new(ACTION_MOVE); - prim->args.path = strdup(action->args.path); + prim->args.uri = strdup(action->args.uri); prim->args.u.move.dest = atomic_action_attic_tmpnam(atomic); atomic_action_free(action); @@ -249,7 +233,7 @@ struct atomic_action *action) { mode_t mode; - struct stat buf; + struct razor_error **error; if (razor_atomic_in_error_state(atomic)) { atomic_action_free(action); @@ -258,21 +242,14 @@ mode = action->args.u.create_dir.mode & (S_IRWXU | S_IRWXG | S_IRWXO); - if (!mkdir(action->args.path, mode)) + if (atomic->error) + error = NULL; + else + error = &atomic->error; + + if (!razor_uri_mkdir(action->args.uri, mode, error)) return action; - if (errno != EEXIST || stat(action->args.path, &buf)) { - if (!atomic->error) - atomic->error = razor_error_new_posix(action->args.path); - atomic_action_free(action); - return NULL; - } - - if (!S_ISDIR(buf.st_mode) && !atomic->error) - atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST, - action->args.path, - "Not a directory"); - atomic_action_free(action); return NULL; } @@ -285,9 +262,9 @@ return NULL; } - if (rmdir(action->args.path) < 0) { + if (rmdir(action->args.uri) < 0) { if (!atomic->error) - atomic->error = razor_error_new_posix(action->args.path); + atomic->error = razor_error_new_posix(action->args.uri); atomic_action_free(action); return NULL; } else @@ -306,10 +283,10 @@ return NULL; } - r = symlink(action->args.u.create_symlink.target, action->args.path); + r = symlink(action->args.u.create_symlink.target, action->args.uri); if (r < 0) { if (!atomic->error) - atomic->error = razor_error_new_posix(action->args.path); + atomic->error = razor_error_new_posix(action->args.uri); atomic_action_free(action); return NULL; } @@ -321,14 +298,19 @@ atomic_action_remove_symlink(struct razor_atomic *atomic, struct atomic_action *action) { + struct razor_error **error; + if (razor_atomic_in_error_state(atomic)) { atomic_action_free(action); return NULL; } - if (unlink(action->args.path) < 0) { - if (!atomic->error) - atomic->error = razor_error_new_posix(action->args.path); + if (atomic->error) + error = NULL; + else + error = &atomic->error; + + if (razor_uri_unlink(action->args.uri, error)) { atomic_action_free(action); return NULL; } @@ -338,52 +320,16 @@ #endif static int -move_file(struct razor_atomic *atomic, const char *path, const char *dest) +move_file(struct razor_atomic *atomic, const char *uri, const char *dest) { -#ifdef MSWIN_API - wchar_t *oldbuf, *newbuf; - const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; + struct razor_error **error; - newbuf = razor_utf8_to_utf16(dest, -1); - oldbuf = razor_utf8_to_utf16(path, -1); + if (atomic->error) + error = NULL; + else + error = &atomic->error; - /* - * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will - * cover every case we care about _except_ replacing an empty - * directory with a file. Calling RemoveDirectory() will deal - * with this case while having no effect in all other cases. - */ - (void)RemoveDirectoryW(newbuf); - - if (!MoveFileExW(oldbuf, newbuf, flags)) { - if (!atomic->error) - atomic->error = razor_error_new_mswin(newbuf, - GetLastError()); - return -1; - } - - free(newbuf); - free(oldbuf); -#else - int code; - const char *object; - - if (rename(path, dest)) { - if (!atomic->error) { - code = errno; - if (access(path, F_OK) < 0) - object = path; - else - object = dest; - atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, - code, object, - strerror(code)); - } - return -1; - } -#endif - - return 0; + return razor_uri_move(uri, dest, error); } static struct atomic_action * @@ -394,7 +340,7 @@ return NULL; } - if (move_file(atomic, action->args.path, action->args.u.move.dest)) { + if (move_file(atomic, action->args.uri, action->args.u.move.dest)) { atomic_action_free(action); return NULL; } @@ -410,7 +356,7 @@ return NULL; } - if (move_file(atomic, action->args.u.move.dest, action->args.path)) { + if (move_file(atomic, action->args.u.move.dest, action->args.uri)) { atomic_action_free(action); return NULL; } diff -r 7442b30ecaae -r 008c75a5e08d librazor/atomic-emulate.c --- a/librazor/atomic-emulate.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/atomic-emulate.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 J. Ali Harlow + * Copyright (C) 2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +24,7 @@ #include #include #include -#include -#include #include -#include -#include -#include #include "razor-internal.h" /* @@ -53,24 +48,23 @@ static void recursive_remove(const char *directory) { - DIR *dp; - struct dirent *dirp; - char *buf; + void *dp; + char *name, *buf; - dp = opendir(directory); - while((dirp = readdir(dp))) { - if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) { - buf = malloc(strlen(directory) + strlen(dirp->d_name) - + 2); - sprintf(buf, "%s/%s", directory, dirp->d_name); - if (remove(buf) < 0) + dp = razor_uri_opendir(directory, NULL); + + if (dp) { + while((name = razor_uri_readdir(dp, NULL))) { + buf = razor_concat(directory, "/", name, NULL); + free(name); + if (razor_uri_unlink(buf, NULL) < 0) recursive_remove(buf); free(buf); } + + razor_uri_closedir(dp, NULL); } - closedir(dp); - rmdir(directory); } @@ -129,53 +123,6 @@ free(atomic); } -#ifndef MSWIN_API -static char *absolute_path(const char *path) -{ - int len; - char *result, *subpath, *p, *s, *t; - - result = realpath(path, NULL); - - if (!result && errno == ENOENT) { - p = strdup(path); - s = strrchr(p, '/'); - - while (s) { - if (s == p) { - result = strdup("/"); - break; - } - - *s = '\0'; - subpath = realpath(p, NULL); - - if (subpath) { - *s = '/'; - len = strlen(subpath); - result = malloc(len + strlen(s) + 1); - memcpy(result, subpath, len); - strcpy(result + len, s); - free(subpath); - break; - } else if (errno != ENOENT) - break; - - t = strrchr(p, '/'); - *s = '/'; - s = t; - } - - if (!s) - result = realpath(".", NULL); - - free(p); - } - - return result; -} -#endif - /* * We need a toplevel directory in which to hold temporary files * before they are committed. Since we can generally assume that @@ -186,14 +133,9 @@ */ static int -razor_atomic_set_toplevel_from_path(struct razor_atomic *atomic, - const char *path) +razor_atomic_set_toplevel_from_uri(struct razor_atomic *atomic, + const char *uri) { -#ifndef MSWIN_API - dev_t filesystem; - struct stat buf; -#endif - if (razor_atomic_in_error_state(atomic)) return -1; @@ -201,231 +143,113 @@ return 0; #ifdef MSWIN_API - if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\' - && strchr(path+3,'\\')) { - /* We have a UNC path: \\servername\sharename... */ - const char *sharename, *root; - int disklen; - - sharename = strchr(path+3,'\\')+1; - root = strchr(sharename,'\\'); - if (root) - disklen = root - path; - else - disklen = strlen(path); - - atomic->toplevel = - malloc(disklen + strlen("\\atomic-XXXXXX") + 1); - memcpy(atomic->toplevel, path, disklen); - strcpy(atomic->toplevel + disklen, "\\atomic-XXXXXX"); - } else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') && - path[1]==':') { - atomic->toplevel = strdup("X:\\atomic-XXXXXX"); - *atomic->toplevel = *path; - } else { - DWORD n; - wchar_t *buf; - char *dir; - - n = GetCurrentDirectoryW(0, NULL); - buf = malloc(n * sizeof(wchar_t)); - - if (GetCurrentDirectoryW(n, buf)) { - dir = razor_utf16_to_utf8(buf, n - 1); - razor_atomic_set_toplevel_from_path(atomic, dir); - - free(dir); - free(buf); - return; - } else - atomic->toplevel = strdup("C:\\atomic-XXXXXX"); - - free(buf); - } + atomic->toplevel = razor_uri_mkdtemp_near(uri, "atomic-XXXXXX", + &atomic->error); #else - { - /* - * Find the mount point (assuming we can write to the - * whole filesystem). Otherwise stop at the first - * unwritable directory and take one step back. - */ - char *s, *abspath, saved; - int len, can_step_back = 0; - - abspath = absolute_path(path); - if (!abspath) { - atomic->error = razor_error_new_posix(path); - return -1; - } - - if (stat(abspath, &buf) < 0) { - if (errno == ENOENT) - filesystem = 0; - else { - atomic->error = razor_error_new_posix(abspath); - free(abspath); - return -1; - } - } else - filesystem = buf.st_dev; - - len = strlen(abspath); - while(len > 1 && (s = strrchr(abspath, '/'))) { - if (s == abspath) { - saved = s[1]; - s[1] = '\0'; - len = s + 1 - abspath; - } else { - s[0] = '\0'; - len = s - abspath; - } - - if (stat(abspath, &buf) < 0) { - if (errno == ENOENT) - continue; - else { - atomic->error = razor_error_new_posix(abspath); - free(abspath); - return -1; - } - } else if (!filesystem) - filesystem = buf.st_dev; - - if (buf.st_dev != filesystem || access(abspath, W_OK)) { - if (can_step_back) { - if (s == abspath) - s[1] = saved; - else - s[0] = '/'; - } - len = strlen(abspath); - break; - } else - can_step_back = 1; - } - - if (len == 1) - len = 0; /* Avoid an unslightly double slash. */ - atomic->toplevel = malloc(len + strlen("/.atomic-XXXXXX") + 1); - memcpy(atomic->toplevel, abspath, len); - strcpy(atomic->toplevel + len, "/.atomic-XXXXXX"); - - free(abspath); - } + atomic->toplevel = razor_uri_mkdtemp_near(uri, ".atomic-XXXXXX", + &atomic->error); #endif - if (!mkdtemp(atomic->toplevel)) { - int err = errno; - -#ifdef EACCES - if (err == EACCES) { - char *s = strdup("atomic-XXXXXX"); - -#ifndef MSWIN_API - if (stat(".", &buf) < 0) { - atomic->error = razor_error_new_posix("."); - free(s); - free(atomic->toplevel); - atomic->toplevel = NULL; - return -1; - } - if (buf.st_dev != filesystem) - /* - * Don't use a different filesystem. It will - * only fail later on (in rename) and cause - * an unhelpful error message (EXDEV). - */ - free(s); - else -#endif - if (mkdtemp(s)) { - free(atomic->toplevel); - atomic->toplevel = s; - return 0; - } else - free(s); - } -#endif - - atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, err, - atomic->toplevel, - strerror(err)); - - free(atomic->toplevel); - atomic->toplevel = NULL; - } - return !atomic->toplevel; } +/* + * If root_uri is empty, then uri can be a URI (but not a relative-ref; ie., + * a scheme must be specified). If root_uri is non-empty, then it must be a + * URI (but not a relative-ref) and uri must be a non-empty path. + */ RAZOR_EXPORT int -razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root, - const char *path) +razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root_uri, + const char *uri) { struct atomic_action *a; + struct razor_uri ru; + struct razor_error *tmp_error = NULL; + char *fakeroot = NULL; - razor_atomic_set_toplevel_from_path(atomic, *root ? root : path); + razor_atomic_set_toplevel_from_uri(atomic, *root_uri ? root_uri : uri); if (razor_atomic_in_error_state(atomic)) return -1; + if (!*root_uri) { + if (razor_uri_parse(&ru, uri, &tmp_error)) { + razor_atomic_propagate_error(atomic, tmp_error, NULL); + return -1; + } + if (*ru.path == '/') { + free(ru.path); + ru.path = strdup("/"); + } else { + free(ru.path); + ru.path = strdup(""); + } + fakeroot = razor_uri_recompose(&ru); + razor_uri_destroy(&ru); + root_uri = fakeroot; + uri += strlen(fakeroot); + } + a = atomic_action_new(ACTION_MAKE_DIRS); - a->args.path = strdup(path); - a->args.u.make_dirs.root = strdup(root); + a->args.uri = strdup(uri); + a->args.u.make_dirs.root = strdup(root_uri); + atomic->actions = atomic_action_list_prepend(atomic->actions, a); + + if (fakeroot) + free(fakeroot); + + return 0; +} + +RAZOR_EXPORT int +razor_atomic_remove(struct razor_atomic *atomic, const char *uri) +{ + struct atomic_action *a; + + razor_atomic_set_toplevel_from_uri(atomic, uri); + + if (razor_atomic_in_error_state(atomic)) + return -1; + + a = atomic_action_new(ACTION_REMOVE); + a->args.uri = strdup(uri); atomic->actions = atomic_action_list_prepend(atomic->actions, a); return 0; } RAZOR_EXPORT int -razor_atomic_remove(struct razor_atomic *atomic, const char *path) +razor_atomic_rename_file(struct razor_atomic *atomic, const char *old_uri, + const char *new_uri) { struct atomic_action *a; - razor_atomic_set_toplevel_from_path(atomic, path); + razor_atomic_set_toplevel_from_uri(atomic, new_uri); if (razor_atomic_in_error_state(atomic)) return -1; - a = atomic_action_new(ACTION_REMOVE); - a->args.path = strdup(path); + a = atomic_action_new(ACTION_MOVE); + a->args.uri = strdup(old_uri); + a->args.u.move.dest = strdup(new_uri); atomic->actions = atomic_action_list_prepend(atomic->actions, a); return 0; } RAZOR_EXPORT int -razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath, - const char *newpath) -{ - struct atomic_action *a; - - razor_atomic_set_toplevel_from_path(atomic, newpath); - - if (razor_atomic_in_error_state(atomic)) - return -1; - - a = atomic_action_new(ACTION_MOVE); - a->args.path = strdup(oldpath); - a->args.u.move.dest = strdup(newpath); - atomic->actions = atomic_action_list_prepend(atomic->actions, a); - - return 0; -} - -RAZOR_EXPORT int -razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname, +razor_atomic_create_dir(struct razor_atomic *atomic, const char *uri, mode_t mode) { struct atomic_action *a; - razor_atomic_set_toplevel_from_path(atomic, dirname); + razor_atomic_set_toplevel_from_uri(atomic, uri); if (razor_atomic_in_error_state(atomic)) return -1; a = atomic_action_new(ACTION_CREATE_DIR); - a->args.path = strdup(dirname); + a->args.uri = strdup(uri); a->args.u.create_dir.mode = mode; atomic->actions = atomic_action_list_prepend(atomic->actions, a); @@ -434,12 +258,12 @@ RAZOR_EXPORT int razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target, - const char *path) + const char *uri) { #if HAVE_SYMLINK struct atomic_action *a; - razor_atomic_set_toplevel_from_path(atomic, path); + razor_atomic_set_toplevel_from_uri(atomic, uri); #endif if (razor_atomic_in_error_state(atomic)) @@ -447,7 +271,7 @@ #if HAVE_SYMLINK a = atomic_action_new(ACTION_CREATE_SYMLINK); - a->args.path = strdup(path); + a->args.uri = strdup(uri); a->args.u.create_symlink.target = strdup(target); atomic->actions = atomic_action_list_prepend(atomic->actions, a); @@ -462,28 +286,27 @@ } RAZOR_EXPORT int -razor_atomic_create_file(struct razor_atomic *atomic, const char *filename, +razor_atomic_create_file(struct razor_atomic *atomic, const char *uri, mode_t mode) { int fd; struct atomic_action *a; char *tmpnam; - razor_atomic_set_toplevel_from_path(atomic, filename); + razor_atomic_set_toplevel_from_uri(atomic, uri); if (razor_atomic_in_error_state(atomic)) return -1; tmpnam = atomic_action_attic_tmpnam(atomic); - fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + fd = razor_uri_open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + mode & (S_IRWXU | S_IRWXG | S_IRWXO), + &atomic->error); - if (fd == -1) - atomic->error = razor_error_new_posix(filename); - else { + if (fd >= 0) { a = atomic_action_new(ACTION_MOVE); - a->args.path = tmpnam; - a->args.u.move.dest = strdup(filename); + a->args.uri = tmpnam; + a->args.u.move.dest = strdup(uri); atomic->actions = atomic_action_list_prepend(atomic->actions, a); } diff -r 7442b30ecaae -r 008c75a5e08d librazor/atomic-ktm.c --- a/librazor/atomic-ktm.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/atomic-ktm.c Mon Jul 04 10:48:18 2016 +0100 @@ -24,10 +24,8 @@ #include #include #include +#include #include -#include -#include -#include #include #include #include diff -r 7442b30ecaae -r 008c75a5e08d librazor/atomic-none.c --- a/librazor/atomic-none.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/atomic-none.c Mon Jul 04 10:48:18 2016 +0100 @@ -244,8 +244,8 @@ if (razor_atomic_in_error_state(atomic)) return -1; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + fd = razor_uri_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (fd == -1) atomic->error = razor_error_new_posix(filename); diff -r 7442b30ecaae -r 008c75a5e08d librazor/atomic.c --- a/librazor/atomic.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/atomic.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 J. Ali Harlow + * Copyright (C) 2011-2012, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,9 +23,6 @@ #include #include #include -#include -#include -#include #include #include @@ -81,8 +78,15 @@ razor_atomic_propagate_error(struct razor_atomic *atomic, struct razor_error *error, const char *summary) { - if (!atomic->error) - atomic->error = razor_error_dup(error, summary); + if (!atomic->error) { + if (!summary) { + atomic->error = error; + return; + } else + atomic->error = razor_error_dup(error, summary); + } + + razor_error_free(error); } RAZOR_EXPORT int diff -r 7442b30ecaae -r 008c75a5e08d librazor/dump.c --- a/librazor/dump.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/dump.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 J. Ali Harlow + * Copyright (C) 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -356,11 +356,11 @@ } RAZOR_EXPORT int -razor_dump_database(FILE *fp, const char *root, const char *filename, +razor_dump_database(FILE *fp, const char *root_uri, const char *filename, struct razor_error **error) { int i; - char *s, *path, *data; + char *s, *uri, *data; struct array pool = { 0, }; struct array string_pool = { 0, }; struct array file_string_pool = { 0, }; @@ -377,11 +377,14 @@ if (!filename) filename = "system.rzdb"; - s = razor_concat(razor_get_database_path(), "/", filename, NULL); - path = razor_path_add_root(s, root); - free(s); - contents = razor_file_get_contents(path, &length, 0, error); - free(path); + uri = razor_resolve_database_file(root_uri, filename, error); + + if (!uri) + return -1; + + contents = razor_uri_get_contents(uri, &length, 0, error); + + free(uri); if (!contents) return -1; @@ -482,7 +485,7 @@ fprintf(fp, "%05lX EOF\n", (unsigned long)n); - razor_file_free_contents(contents, length); + razor_uri_free_contents(contents, length); return 0; } diff -r 7442b30ecaae -r 008c75a5e08d librazor/path.c --- a/librazor/path.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/path.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 J. Ali Harlow + * Copyright (C) 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,78 +19,10 @@ #include "config.h" #include #include +#include #include "razor.h" #include "razor-internal.h" - -/** - * razor_path_add_root: - * - * Adds a root to a path. path must be an absolute pathname. In POSIX - * environments this is equivalent to the concationation of root and path. - * In Microsoft Windows an adjustment may need to be made for a drive letter - * in path (which will be dropped). - * - * Returns: The new pathname. - **/ -RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root) -{ - if (root && *root) - return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL); - else - return strdup(path); -} - -#if 0 - -/* - * This should work, but for some reason PathCreateFromUrlW() - * treats the percent-encoded bytes as being in CP 850 rather - * than UTF-8 as expected even if we set the codepage. - */ -RAZOR_EXPORT char *razor_path_from_url(const char *url) -{ - UINT saved_cp; - HRESULT result; - DWORD len = MAX_PATH; - wchar_t *url16; - wchar_t path16[MAX_PATH]; - char *path; - - url16 = razor_utf8_to_utf16(url, -1); - - saved_cp = GetConsoleCP(); - SetConsoleCP(CP_UTF8); - - result = PathCreateFromUrlW(url16, path16, &len, NULL); - - SetConsoleCP(saved_cp); - - if (result == S_OK) - path = razor_utf16_to_utf8(path16, len); - else - path = NULL; - - free(url16); - - return path; -} - -#else - -#ifdef MSWIN_API -static int is_ascii_letter(char c) -{ - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); -} -#endif - -static int xdigit_value(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else - return (c | 0x20) - 'a' + 10; -} +#include "uri.h" static int valid_unicode(unsigned unicode) { @@ -101,54 +33,74 @@ return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000); } -RAZOR_EXPORT char *razor_path_from_url(const char *url) +char *razor_path_from_parsed_uri(const struct razor_uri *ru, + struct razor_error **error) { int continuation_bytes = 0; - char *path, *p; + char *path, *p, *s, *uri; unsigned char c; unsigned unicode; - if (strncmp(url, "file://", 7) == 0) - url += 7; - else + if (!ru->scheme) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, uri, + "URI does not include a scheme"); + free(uri); return NULL; + } - if (strncmp(url, "localhost/", 10) == 0) - url += 9; - else if (strncmp(url, "/", 1) != 0) + if (strcmp(ru->scheme, "file")) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri, + "Not a file URI"); + free(uri); return NULL; + } + if (ru->host && *ru->host && strcmp(ru->host, "localhost") || + ru->userinfo || ru->port) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri, + "URI refers to a non-local file"); + free(uri); + return NULL; + } + + s = ru->path; #ifdef MSWIN_API /* - * Under MS-Windows, file:///c:/xxx maps to c:/xxx + * Under MS-Windows, a path of /c:/xxx maps to c:/xxx * Note that PathCreateFromUrl converts / to \ as well. */ - if (is_ascii_letter(url[1]) && url[2] == ':' && url[3] == '/') - url++; + if (s[0] == '/' && is_alpha(s[1]) && s[2] == ':' && s[3] == '/') + s++; #endif - p = path = malloc(strlen(url) + 1); + p = path = malloc(strlen(s) + 1); - while(*url) { - if (*url >= 0x7F || *url < 0x20) { - free(path); - return NULL; - } else if (*url != '%') { - if (continuation_bytes) { - free(path); - return NULL; - } else - *p++ = *url++; - } else if (isxdigit(url[1]) && isxdigit(url[2])) { - c = xdigit_value(url[1]) * 16 + xdigit_value(url[2]); - if (c == '/') { - free(path); - return NULL; - } else if (!continuation_bytes) { - if (c >= 0xF5 || c == 0xC0 || c == 0xC1) { - free(path); - return NULL; - } else if (c >= 0xF0) { + while (*s) { + if (*s >= 0x7F || *s < 0x20) + break; + else if (*s != '%') { + if (continuation_bytes) + break; + else + *p++ = *s++; + } else { + c = pchar_get_char(s); +#ifdef MSWIN_API + if (c == '/' || c == '\\') +#else + if (c == '/') +#endif + break; + else if (!continuation_bytes) { + if (c >= 0xF5 || c == 0xC0 || c == 0xC1) + break; + else if (c >= 0xF0) { unicode = c & 7; continuation_bytes = 3; } else if (c >= 0xE0) { @@ -158,29 +110,28 @@ unicode = c & 1; continuation_bytes = 1; } - } else if ((c & 0xC0) != 0x80) { - free(path); - return NULL; - } else { + } else if ((c & 0xC0) != 0x80) + break; + else { unicode <<= 6; unicode |= (c & 0x3F); if (!--continuation_bytes && - !valid_unicode(unicode)) { - free(path); - return NULL; - } + !valid_unicode(unicode)) + break; } *p++ = c; - url += 3; - } else { - free(path); - return NULL; + s += 3; } } - if (continuation_bytes) { + if (*s || continuation_bytes) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, + uri, "Illegal character in file URI path"); + free(uri); free(path); return NULL; } @@ -190,4 +141,72 @@ return realloc(path, p - path); } -#endif /* 0 */ +RAZOR_EXPORT char *razor_path_from_uri(const char *uri, + struct razor_error **error) +{ + struct razor_uri ru; + char *path; + + if (razor_uri_parse(&ru, uri, error)) + return NULL; + + path = razor_path_from_parsed_uri(&ru, error); + + razor_uri_destroy(&ru); + + return path; +} + +RAZOR_EXPORT char *razor_path_to_uri(const char *path) +{ + char *uri, *p; + + uri = malloc(6 + 3 * strlen(path) + 1); + + strcpy(uri, "file:"); + + p = uri + 5; + +#ifdef MSWIN_API + /* + * Under MS-Windows, c:/xxx maps to a path of /c:/xxx + */ + if (is_alpha(path[0]) && path[1] == ':' && path[2] == '/') + *p++ = '/'; +#endif + + while(*path) { + if (*path == '/' || is_unreserved(*path) || + is_sub_delim(*path) || *path == ':' || *path == '@') + *p++ = *path; +#ifdef MSWIN_API + else if (*path == '\\') + *p++ = '/'; +#endif + else { + *p++ = '%'; + *p++ = "0123456789ABCDEF"[(*(unsigned char *)path)/16]; + *p++ = "0123456789ABCDEF"[(*(unsigned char *)path)%16]; + } + path++; + } + *p++ = '\0'; + + return realloc(uri, p - uri); +} + +RAZOR_EXPORT char * +razor_path_relative_to_uri(const char *uri, const char *path, + struct razor_error **error) +{ + char *rel_uri, *result; + + /* Strictly wrong if uri isn't a file URI, but probably okay */ + rel_uri = razor_path_to_uri(path); + + result = razor_resolve_uri_root(uri, rel_uri + 5, 1, error); + + free(rel_uri); + + return result; +} diff -r 7442b30ecaae -r 008c75a5e08d librazor/razor-internal.h --- a/librazor/razor-internal.h Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/razor-internal.h Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009, 2011-2012, 2014 J. Ali Harlow + * Copyright (C) 2009, 2011-2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,6 +42,9 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define PADDING(value, base) (-(value) & (base - 1)) #define ALIGN(value, base) ((value) + PADDING(value, base)) + +#define str_has_prefix(s, prefix) (!strncmp(s, prefix, strlen(prefix))) + void *zalloc(size_t size); struct razor_set_section { @@ -181,7 +184,7 @@ }; int -razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive); +razor_set_acquire_lock(struct razor_set *set, const char *path, int exclusive); struct razor_entry * razor_set_find_entry(struct razor_set *set, @@ -206,7 +209,72 @@ ssize_t len, int arg1); int razor_run_script(const char *root, enum razor_property_flags script, - const char *program, const char *body, int arg1); + const char *program, const char *body, int arg1, + struct razor_error **error); + +/* URI functions */ + +struct razor_uri { + char *scheme; + char *userinfo; + char *host; + char *port; + char *path; + char *query; + char *fragment; +}; + +void razor_uri_destroy(struct razor_uri *ru); +int razor_uri_parse_uri(struct razor_uri *ru, const char *uri, int absolute, + struct razor_error **error); +int razor_uri_parse_relative_ref(struct razor_uri *ru, const char *uri, + struct razor_error **error); +int razor_uri_parse(struct razor_uri *ru, const char *uri, + struct razor_error **error); +void razor_uri_normalize(struct razor_uri *ru); +char *razor_uri_get_authority(const struct razor_uri *ru) RAZOR_MALLOC; +char *razor_uri_recompose(const struct razor_uri *ru) RAZOR_MALLOC; +void razor_uri_resolve(struct razor_uri *T, const struct razor_uri *base, + const struct razor_uri *R); + +char *razor_resolve_uri_root(const char *root_uri, const char *relative_uri, + int is_relative, struct razor_error **error) + RAZOR_MALLOC; + +int razor_file_mkdir(const char *path, mode_t mode, struct razor_error **error); +int razor_file_unlink(const char *path, struct razor_error **error); +int razor_file_open(const char *path, int flags, mode_t mode, + struct razor_error **error); +int razor_file_move(const char *path, const char *dest, + struct razor_error **error); +void *razor_file_get_contents(const char *path, size_t *length, int _private, + struct razor_error **error); +int razor_file_free_contents(void *addr, size_t length); +int razor_file_is_directory(const char *path, struct razor_error **error); +char *razor_file_mkdtemp_near(const char *path, const char *_template, + struct razor_error **error); +void *razor_file_opendir(const char *path, struct razor_error **error); +char *razor_file_readdir(void *dir, struct razor_error **error); +int razor_file_closedir(void *dir, struct razor_error **error); + +int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error); +int razor_uri_unlink(const char *uri, struct razor_error **error); +int razor_uri_open(const char *uri, int flags, mode_t mode, + struct razor_error **error); +int razor_uri_move(const char *uri, const char *dest, + struct razor_error **error); +int razor_uri_is_directory(const char *uri, struct razor_error **error); +char *razor_uri_mkdtemp_near(const char *uri, const char *template, + struct razor_error **error) RAZOR_MALLOC; +void *razor_uri_opendir(const char *uri, struct razor_error **error); +char *razor_uri_readdir(void *dir, struct razor_error **error) RAZOR_MALLOC; +int razor_uri_closedir(void *dir, struct razor_error **error); +void *razor_uri_get_contents(const char *uri, size_t *length, int private, + struct razor_error **error); +int razor_uri_free_contents(void *addr, size_t length); + +char *razor_path_from_parsed_uri(const struct razor_uri *ru, + struct razor_error **error); /* Utility functions */ @@ -216,16 +284,6 @@ va_list args); void razor_rpm_get_details_varg(struct razor_rpm *rpm, va_list args); -int razor_create_dir(const char *root, const char *path); -int razor_remove(const char *path); -int razor_write(int fd, const void *data, size_t size); - -void * -razor_file_get_contents(const char *filename, size_t *length, int private, - struct razor_error **error); -int razor_file_free_contents(void *addr, size_t length); - - typedef int (*razor_compare_with_data_func_t)(const void *p1, const void *p, void *data); @@ -267,6 +325,10 @@ if (error) \ *(error) = razor_error_new_posix(object); \ else +#define razor_set_error(error, domain, code, object, str) \ + if (error) \ + *(error) = razor_error_new_str(domain, code, object, str); \ + else #ifdef MSWIN_API struct razor_error *razor_error_new_mswin(const wchar_t *object, DWORD error); @@ -312,7 +374,7 @@ ACTION_MOVE, } type; struct { - char *path; + char *uri; union atomic_action_args { struct { char *root; @@ -359,6 +421,9 @@ }; #endif +char *razor_resolve_database_file(const char *root_uri, const char *filename, + struct razor_error **error); + int razor_allow_all_root_names(void); int razor_valid_root_name(const char *name); diff -r 7442b30ecaae -r 008c75a5e08d librazor/razor.c --- a/librazor/razor.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/razor.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009-2012 J. Ali Harlow + * Copyright (C) 2009-2012, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,10 +28,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include @@ -140,7 +138,7 @@ }; RAZOR_EXPORT int -razor_set_bind_sections(struct razor_set *set, const char *filename, +razor_set_bind_sections(struct razor_set *set, const char *uri, enum razor_set_flags flags, struct razor_error **error) { struct razor_set_section *s, *sections; @@ -156,9 +154,9 @@ return -1; } - file->header = razor_file_get_contents(filename, &file->size, - flags & RAZOR_SET_PRIVATE, - error); + file->header = razor_uri_get_contents(uri, &file->size, + flags & RAZOR_SET_PRIVATE, + error); if (!file->header) { free(file); return -1; @@ -178,9 +176,8 @@ reason = NULL; if (reason) { - razor_set_error(error, RAZOR_GENERAL_ERROR, code, filename, - reason); - razor_file_free_contents(file->header, file->size); + razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason); + razor_uri_free_contents(file->header, file->size); free(file); return -1; } @@ -220,7 +217,7 @@ } RAZOR_EXPORT struct razor_set * -razor_set_open(const char *filename, enum razor_set_flags flags, +razor_set_open(const char *uri, enum razor_set_flags flags, struct razor_error **error) { struct razor_set *set; @@ -234,7 +231,7 @@ set->lock_fd = -1; set->ref_count = 1; - if (razor_set_bind_sections(set, filename, flags, error)) { + if (razor_set_bind_sections(set, uri, flags, error)) { free(set); return NULL; } @@ -242,18 +239,18 @@ } int -razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive) +razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive) { int fd; assert(set != NULL); - if (path) { - fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666); + if (uri) { + fd = razor_uri_open(uri, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, + 0666, NULL); if (fd < 0) return -1; - } else { + } else fd = -1; - } #ifdef MSWIN_API DWORD flags = LOCKFILE_FAIL_IMMEDIATELY; @@ -310,12 +307,12 @@ } else { for (file = set->mapped_files; file != NULL; file = next) { next = file->next; - razor_file_free_contents(file->header, file->size); + razor_uri_free_contents(file->header, file->size); free(file); } } - razor_set_aquire_lock(set, NULL, 0); + razor_set_acquire_lock(set, NULL, 0); free(set); } @@ -390,11 +387,11 @@ RAZOR_EXPORT int razor_set_write(struct razor_set *set, struct razor_atomic *atomic, - const char *filename, uint32_t sections) + const char *uri, uint32_t sections) { int h; - h = razor_atomic_create_file(atomic, filename, + h = razor_atomic_create_file(atomic, uri, S_IRWXU | S_IRWXG | S_IRWXO); if (h < 0) return -1; @@ -636,6 +633,7 @@ struct environment env; struct list *link; const char *prefix; + struct razor_error *tmp_error = NULL; if (stage & RAZOR_STAGE_SCRIPTS) { environment_init(&env); @@ -658,7 +656,12 @@ RAZOR_DETAIL_LAST); retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, - script, install_count); + script, install_count, &tmp_error); + + if (retval < 0) { + razor_atomic_propagate_error(atomic, tmp_error, NULL); + tmp_error = NULL; + } } if (!retval && (stage & RAZOR_STAGE_FILES)) { @@ -690,7 +693,12 @@ RAZOR_DETAIL_LAST); retval |= razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, - script, install_count); + script, install_count, &tmp_error); + + if (retval < 0) { + razor_atomic_propagate_error(atomic, tmp_error, NULL); + tmp_error = NULL; + } } if (stage & RAZOR_STAGE_SCRIPTS) { diff -r 7442b30ecaae -r 008c75a5e08d librazor/razor.h.in --- a/librazor/razor.h.in Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/razor.h.in Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow + * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ #include #include -#include +#include /* GCC extensions */ #if defined(__GNUC__) @@ -130,6 +130,10 @@ *(dest) = razor_error_dup(src, summary); \ else +#define razor_error_matches(error, domain, code) \ + ((error) && razor_error_get_domain(error) == (domain) && \ + razor_error_get_code(error) == (code)) + #define RAZOR_ERROR_DOMAIN(i1,i2,i3,c) \ (((i1)&0xff)<<24|((i2)&0xff)<<16|((i3)&0xff)<<8|(c)&0xff) @@ -145,6 +149,8 @@ RAZOR_GENERAL_ERROR_DATABASE_EXISTS, RAZOR_GENERAL_ERROR_DATABASE_LOCKED, RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + RAZOR_GENERAL_ERROR_BAD_URI, }; int razor_error_get_domain(struct razor_error *error); @@ -195,11 +201,11 @@ * * Returns: non-zero on error. **/ -int razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root, - const char *path); +int razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root_uri, + const char *uri); int razor_atomic_remove(struct razor_atomic *atomic, const char *path); -int razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath, - const char *newpath); +int razor_atomic_rename_file(struct razor_atomic *atomic, const char *old_uri, + const char *new_uri); /** * razor_atomic_create_dir @@ -209,8 +215,8 @@ * * Returns: non-zero on error. */ -int razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname, - mode_t mode); +int razor_atomic_create_dir(struct razor_atomic *atomic, const char *uri, + mode_t mode); /** * razor_atomic_create_symlink @@ -224,7 +230,7 @@ * Returns: non-zero on error. */ int razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target, - const char *path); + const char *uri); /** * razor_atomic_create_file * @@ -234,16 +240,17 @@ * Returns: A handle to be passed to razor_atomic_write() and * razor_atomic_close() or a negative value on error. */ -int razor_atomic_create_file(struct razor_atomic *atomic, const char *filename, - mode_t mode); +int razor_atomic_create_file(struct razor_atomic *atomic, const char *uri, + mode_t mode); int razor_atomic_write(struct razor_atomic *atomic, int handle, - const void *data, size_t size); + const void *data, size_t size); int razor_atomic_close(struct razor_atomic *atomic, int handle); int razor_atomic_sync(struct razor_atomic *atomic, int handle); void razor_atomic_abort(struct razor_atomic *atomic, int domain, int code, - const char *error_msg); -void razor_atomic_propagate_error(struct razor_atomic *atomic, - struct razor_error *error, const char *summary); + const char *error_msg); +void +razor_atomic_propagate_error(struct razor_atomic *atomic, + struct razor_error *error, const char *summary); int razor_atomic_in_error_state(struct razor_atomic *atomic); /** @@ -272,7 +279,7 @@ struct razor_set *razor_set_create_without_root(void); struct razor_set *razor_set_create(void); struct razor_set * -razor_set_open(const char *filename, enum razor_set_flags flags, +razor_set_open(const char *uri, enum razor_set_flags flags, struct razor_error **error); uint32_t razor_set_get_header_version(struct razor_set *set); int razor_set_set_header_version(struct razor_set *set, @@ -283,9 +290,9 @@ struct razor_atomic *atomic, int handle, uint32_t section_mask); int razor_set_write(struct razor_set *set, struct razor_atomic *atomic, - const char *filename, uint32_t setions); + const char *uri, uint32_t setions); int -razor_set_bind_sections(struct razor_set *set, const char *filename, +razor_set_bind_sections(struct razor_set *set, const char *uri, enum razor_set_flags flags, struct razor_error **error); void @@ -506,13 +513,12 @@ const char *path); void razor_relocations_destroy(struct razor_relocations *relocations); -struct razor_rpm *razor_rpm_open(const char *filename, - struct razor_error **error); +struct razor_rpm *razor_rpm_open(const char *uri, struct razor_error **error); void razor_rpm_get_details(struct razor_rpm *rpm, ...); void razor_rpm_set_relocations(struct razor_rpm *rpm, struct razor_relocations *relocations); int razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic, - const char *root, int install_count, + const char *root_uri, int install_count, enum razor_stage_type stage); int razor_rpm_close(struct razor_rpm *rpm); @@ -599,13 +605,13 @@ **/ struct razor_root; -const char *razor_get_database_path(); -void razor_set_database_path(const char *database_path); -int razor_root_create(const char *root, struct razor_error **error); +const char *razor_get_database_uri(void); +void razor_set_database_uri(const char *database_uri); +int razor_root_create(const char *root_uri, struct razor_error **error); struct razor_root * -razor_root_open(const char *root, struct razor_error **error); +razor_root_open(const char *root_uri, struct razor_error **error); struct razor_set * -razor_root_open_read_only(const char *root, struct razor_error **error); +razor_root_open_read_only(const char *root_uri, struct razor_error **error); struct razor_set *razor_root_get_system_set(struct razor_root *root); int razor_root_close(struct razor_root *root); int @@ -613,6 +619,41 @@ struct razor_atomic *atomic); /** + * SECTION:uri-io + * @title: URI Input/Output + * @short_description: Functions to support non-file URI handlers + * + * Libraries that want to support URIs other than file URIs (which razor + * handles internally), can install their own URI handlers. Unsupported + * virtual functions should be set to %NULL. A fallback URI handler (which + * will be used if no scheme-specific handler is found) can be installed + * by passing scheme as %NULL. Finally, URI handlers can be removed by + * passing vtable as %NULL. + **/ + +struct razor_uri_vtable { + unsigned structure_size; + int (*mkdir)(const char *path, mode_t mode, struct razor_error **error); + int (*unlink)(const char *path, struct razor_error **error); + int (*open)(const char *path, int flags, mode_t mode, + struct razor_error **error); + int (*move)(const char *path, const char *dest, + struct razor_error **error); + void *(*get_contents)(const char *path, size_t *length, int _private, + struct razor_error **error); + int (*free_contents)(void *addr, size_t length); + int (*is_directory)(const char *path, struct razor_error **error); + char *(*mkdtemp_near)(const char *path, const char *_template, + struct razor_error **error); + void *(*opendir)(const char *path, struct razor_error **error); + char *(*readdir)(void *dir, struct razor_error **error); + int (*closedir)(void *dir, struct razor_error **error); +}; + +int razor_uri_set_vtable(const char *scheme, struct razor_uri_vtable *vtable, + struct razor_error **error); + +/** * SECTION:misc * @title: Miscellaneous Functions * @short_description: Various helper functions @@ -636,12 +677,15 @@ char *razor_concat(const char *s, ...) RAZOR_MALLOC RAZOR_NULL_TERMINATED; -char *razor_path_add_root(const char *path, const char *root) RAZOR_MALLOC; -char *razor_path_from_url(const char *url) RAZOR_MALLOC; +char *razor_path_from_uri(const char *uri, struct razor_error **error) + RAZOR_MALLOC; +char *razor_path_to_uri(const char *path) RAZOR_MALLOC; +char *razor_path_relative_to_uri(const char *file_uri, const char *path, + struct razor_error **error) RAZOR_MALLOC; const char *razor_system_arch(void); -int razor_dump_database(FILE *fp, const char *root, const char *filename, +int razor_dump_database(FILE *fp, const char *root_uri, const char *filename, struct razor_error **error); #endif /* _RAZOR_H_ */ diff -r 7442b30ecaae -r 008c75a5e08d librazor/root.c --- a/librazor/root.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/root.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow + * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -59,102 +58,130 @@ */ static const char system_lock_filename[] = "system-next.rzdb"; #ifdef MSWIN_API -#define RAZOR_DATABASE_PATH NULL +#define RAZOR_DATABASE_URI NULL #else -#define RAZOR_DATABASE_PATH "/var/lib/razor" +/* + * The non-MSWIN default is a relative-ref and thus affected by the root + */ +#define RAZOR_DATABASE_URI "var/lib/razor" #endif -static char *razor_database_path = RAZOR_DATABASE_PATH; -static int razor_database_path_alloced = FALSE; +static char *razor_database_uri = RAZOR_DATABASE_URI; +static int razor_database_uri_alloced = FALSE; struct razor_root { struct razor_set *system; - char *path; + char *uri; }; static void razor_root_init(void) { #ifdef MSWIN_API - static char database_path[MAX_PATH]; - if (!razor_database_path) { + /* + * The MSWIN default is an absolute-URI and thus unaffected by the root + */ + char database_path[MAX_PATH]; + if (!razor_database_uri) { SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0, database_path); strcat(database_path, "\\Razor"); - razor_database_path = database_path; - razor_database_path_alloced = FALSE; + razor_database_uri = razor_path_to_uri(database_path); + razor_database_uri_alloced = TRUE; } #endif } -RAZOR_EXPORT const char * -razor_get_database_path() +RAZOR_EXPORT const char *razor_get_database_uri(void) { razor_root_init(); - - return razor_database_path; + return razor_database_uri; } RAZOR_EXPORT void -razor_set_database_path(const char *database_path) +razor_set_database_uri(const char *database_uri) { - if (razor_database_path_alloced) - free(razor_database_path); + if (razor_database_uri_alloced) + free(razor_database_uri); - if (database_path) { - razor_database_path = strdup(database_path); - razor_database_path_alloced = TRUE; + if (database_uri) { + razor_database_uri = strdup(database_uri); + razor_database_uri_alloced = TRUE; } else { - razor_database_path = RAZOR_DATABASE_PATH; - razor_database_path_alloced = FALSE; + razor_database_uri = RAZOR_DATABASE_URI; + razor_database_uri_alloced = FALSE; } } +char *razor_resolve_database_file(const char *root_uri, const char *filename, + struct razor_error **error) +{ + char *s, *uri; + + razor_root_init(); + + s = razor_concat(razor_database_uri, "/", filename, NULL); + + uri = razor_resolve_uri_root(root_uri, s, -1, error); + + free(s); + + return uri; +} + RAZOR_EXPORT int -razor_root_create(const char *root, struct razor_error **error) +razor_root_create(const char *root_uri, struct razor_error **error) { - int retval; - struct stat buf; + int retval, is_within_root, is_directory; struct razor_set *set; struct razor_atomic *atomic; - char *file, *path; + struct razor_error *tmp_err = NULL; + char *uri; - assert (root != NULL); + uri = razor_resolve_database_file(root_uri, system_repo_filename, + error); - razor_root_init(); - if (root[0] == '\0') { - /* root is file system root */ - } else if (stat(root, &buf) < 0) { - if (mkdir(root, 0777) < 0) { - razor_set_error(error, RAZOR_POSIX_ERROR, errno, root, + if (!uri) + return -1; + + if (razor_uri_is_directory(uri, NULL) >= 0) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL, + "A razor install root is already initialized"); + free(uri); + return -1; + } + + is_within_root = root_uri && strchr(root_uri, '/') && + str_has_prefix(uri, root_uri); + + atomic = razor_atomic_open("Create initial package set"); + + if (is_within_root) { + is_directory = razor_uri_is_directory(root_uri, NULL); + + if (!is_directory) { + razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, + root_uri, "Not a directory"); + return -1; + } else if (is_directory < 0 && + razor_uri_mkdir(root_uri, 0777, &tmp_err) < 0) { + razor_set_error(error, + razor_error_get_domain(tmp_err), + razor_error_get_code(tmp_err), + root_uri, "Could not create install root"); return -1; } - } else if (!S_ISDIR(buf.st_mode)) { - razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, root, - "Not a directory"); - return -1; - } - file = razor_concat(razor_database_path, "/", system_repo_filename, - NULL); - path = razor_path_add_root(file, root); - retval = !stat(path, &buf); - if (retval) { - razor_set_error(error, RAZOR_GENERAL_ERROR, - RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL, - "A razor install root is already initialized"); - free(path); - free(file); - return retval; - } + razor_atomic_make_dirs(atomic, root_uri, + uri + strlen(root_uri)); + } else + razor_atomic_make_dirs(atomic, "", uri); - atomic = razor_atomic_open("Create initial package set"); - razor_atomic_make_dirs(atomic, root, file); set = razor_set_create(); - razor_set_write(set, atomic, path, RAZOR_SECTION_ALL); - free(path); - free(file); + razor_set_write(set, atomic, uri, RAZOR_SECTION_ALL); + free(uri); retval = razor_atomic_commit(atomic); if (retval) razor_propagate_error(error, @@ -167,17 +194,21 @@ } RAZOR_EXPORT struct razor_root * -razor_root_open(const char *root, struct razor_error **error) +razor_root_open(const char *root_uri, struct razor_error **error) { struct razor_root *image; - char *s, *lock_path; + char *lock_uri; int r; - assert (root != NULL); + lock_uri = razor_resolve_database_file(root_uri, system_lock_filename, + error); - razor_root_init(); + if (!lock_uri) + return NULL; + image = malloc(sizeof *image); if (image == NULL) { + free(lock_uri); razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, "Not enough memory"); return NULL; @@ -186,35 +217,37 @@ image->system = razor_set_create_without_root(); if (image->system == NULL) { free(image); + free(lock_uri); razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, "Not enough memory"); return NULL; } - s = razor_concat(razor_database_path, "/", system_lock_filename, NULL); - lock_path = razor_path_add_root(s, root); - free(s); + r = razor_set_acquire_lock(image->system, lock_uri, 1); - r = razor_set_aquire_lock(image->system, lock_path, 1); - - free(lock_path); + free(lock_uri); if (r < 0) { razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL, - "Failed to aquire exclusive system lock"); + "Failed to acquire exclusive system lock"); razor_set_unref(image->system); free(image); return NULL; } - s = razor_concat(razor_database_path, "/", system_repo_filename, NULL); - image->path = razor_path_add_root(s, root); - free(s); + image->uri = razor_resolve_database_file(root_uri, system_repo_filename, + error); - if (razor_set_bind_sections(image->system, image->path, + if (!image->uri) { + razor_set_unref(image->system); + free(image); + return NULL; + } + + if (razor_set_bind_sections(image->system, image->uri, RAZOR_SET_PRIVATE, error)) { - free(image->path); + free(image->uri); razor_set_unref(image->system); free(image); return NULL; @@ -224,46 +257,47 @@ } RAZOR_EXPORT struct razor_set * -razor_root_open_read_only(const char *root, struct razor_error **error) +razor_root_open_read_only(const char *root_uri, struct razor_error **error) { - char *s, *path; + int r; + char *uri; struct razor_set *set; - assert (root != NULL); + uri = razor_resolve_database_file(root_uri, system_lock_filename, + error); - razor_root_init(); + if (!uri) + return NULL; + set = razor_set_create_without_root(); if (set == NULL) { + free(uri); razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, "Not enough memory"); return NULL; } - s = razor_concat(razor_database_path, "/", system_lock_filename, NULL); - path = razor_path_add_root(s, root); - free(s); + r = razor_set_acquire_lock(set, uri, 0); - if (razor_set_aquire_lock(set, path, 0) < 0) { + free(uri); + + if (r < 0) { razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL, - "Failed to aquire non-exclusive system lock"); - free(path); + "Failed to acquire non-exclusive system lock"); razor_set_unref(set); return NULL; } - free(path); + uri = razor_resolve_database_file(root_uri, system_repo_filename, + error); - s = razor_concat(razor_database_path, "/", system_repo_filename, NULL); - path = razor_path_add_root(s, root); - free(s); - - if (razor_set_bind_sections(set, path, 0, error)) { + if (!uri || razor_set_bind_sections(set, uri, 0, error)) { razor_set_unref(set); set = NULL; } - free(path); + free(uri); return set; } @@ -282,7 +316,7 @@ assert (root != NULL); razor_set_unref(root->system); - free(root->path); + free(root->uri); free(root); return 0; @@ -297,7 +331,7 @@ assert (root != NULL); assert (next != NULL); - handle = razor_atomic_create_file(atomic, root->path, + handle = razor_atomic_create_file(atomic, root->uri, S_IRWXU | S_IRWXG | S_IRWXO); if (handle < 0) return handle; diff -r 7442b30ecaae -r 008c75a5e08d librazor/rpm.c --- a/librazor/rpm.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/rpm.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow + * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,10 @@ #include #include #include -#include -#include #if HAVE_SYS_WAIT_H #include #endif #include -#include #include #if MSWIN_API #include /* For ntohl() */ @@ -620,7 +617,7 @@ } RAZOR_EXPORT struct razor_rpm * -razor_rpm_open(const char *filename, struct razor_error **error) +razor_rpm_open(const char *uri, struct razor_error **error) { struct rpm_lead *lead; struct razor_rpm *rpm; @@ -628,7 +625,7 @@ unsigned int count, i, nindex, hsize; const char *name, *prefix; - assert (filename != NULL); + assert (uri != NULL); rpm = zalloc(sizeof *rpm); if (rpm == NULL) { @@ -638,7 +635,7 @@ } memset(rpm, 0, sizeof *rpm); - rpm->map = razor_file_get_contents(filename, &rpm->size, 0, error); + rpm->map = razor_uri_get_contents(uri, &rpm->size, 0, error); if (!rpm->map) { free(rpm); return NULL; @@ -646,11 +643,11 @@ lead = rpm->map; if (rpm->size < RPM_LEAD_SIZE || - strncmp(lead->magic,RPM_LEAD_MAGIC,4) || lead->major != 3) { + strncmp((char *)lead->magic,RPM_LEAD_MAGIC,4) || lead->major != 3) { razor_rpm_close(rpm); razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, - filename, "Not a recognized RPM format file"); + uri, "Not a recognized RPM format file"); return NULL; } @@ -682,8 +679,7 @@ razor_rpm_close(rpm); razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, - filename, - "Old filenames not supported"); + uri, "Old filenames not supported"); return NULL; } } @@ -704,8 +700,7 @@ razor_rpm_close(rpm); razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, - filename, - "Default prefix not supported"); + uri, "Default prefix not supported"); return NULL; } } @@ -748,7 +743,7 @@ #define RESERVED 0xE0 /* bits 5..7: reserved */ struct installer { - const char *root; + const char *root_uri; struct razor_rpm *rpm; struct razor_atomic *atomic; z_stream stream; @@ -808,13 +803,47 @@ static int create_path(struct installer *installer, const char *path, unsigned int mode) { - char *s, *buffer; - int h, ret; + const char *s, *relative; + char *uri, *buffer; + int h, ret, is_within_root; + struct razor_error *tmp_error = NULL; - if (razor_atomic_make_dirs(installer->atomic, installer->root, path)) + uri = razor_path_to_uri(path); + + if (str_has_prefix(uri, "file:///")) + relative = uri + 8; + else if (str_has_prefix(uri, "file:/")) + relative = uri + 6; + else if (str_has_prefix(uri, "file:")) + relative = uri + 5; + else if (str_has_prefix(uri, "/")) + relative = uri + 1; + else + relative = uri; + + buffer = razor_resolve_uri_root(installer->root_uri, relative, 1, + &tmp_error); + + if (!buffer) { + razor_atomic_propagate_error(installer->atomic, tmp_error, + NULL); + free(uri); return -1; + } - buffer = razor_concat(installer->root, path, NULL); + is_within_root = installer->root_uri && + str_has_prefix(buffer, installer->root_uri); + + if (is_within_root) + ret = razor_atomic_make_dirs(installer->atomic, + installer->root_uri, relative); + else + ret = razor_atomic_make_dirs(installer->atomic, "", buffer); + + free(uri); + + if (ret) + return ret; switch (mode >> 12) { case REG: @@ -831,7 +860,8 @@ installer->length)) return -1; } - return razor_atomic_close(installer->atomic, h); + ret = razor_atomic_close(installer->atomic, h); + break; case XDIR: ret = razor_atomic_create_dir(installer->atomic, buffer, mode); free(buffer); @@ -842,16 +872,17 @@ return -1; if (installer->length >= sizeof installer->buffer) { razor_atomic_abort(installer->atomic, - RAZOR_GENERAL_ERROR, - RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, - "Link target too long"); + RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, + "Link target too long"); return -1; } installer->buffer[installer->length] = '\0'; ret = razor_atomic_create_symlink(installer->atomic, - (const char *)installer->buffer, buffer); + (const char *)installer->buffer, + buffer); free(buffer); - return ret; + break; #else s = "Symbolic links"; goto unsupported; @@ -861,9 +892,9 @@ unsupported: free(buffer); buffer = razor_concat(s, " are not supported on this platform", - NULL); + NULL); razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR, - RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, buffer); + RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, buffer); free(buffer); return -1; case CDEV: @@ -878,9 +909,12 @@ default: free(buffer); razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR, - RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, "Unknown file type"); + RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, + "Unknown file type"); return -1; } + + return ret; } static int chroot_push(const char *root) @@ -912,12 +946,14 @@ } static int -run_script_lua(const char *root, unsigned int script_tag, const char *script, - int arg1) +run_script_lua(const char *root_uri, unsigned int script_tag, + const char *script, int arg1, struct razor_error **error) { int root_fd, retval; + const char *name; #if HAVE_LUA - const char *name; + char *root; +#endif switch(script_tag) { case RPMTAG_PREIN: @@ -936,12 +972,19 @@ name = "script"; break; } - root_fd = chroot_push(root); + +#if HAVE_LUA + root = razor_path_from_uri(root_uri, error); + if (!root) + return -1; + root_fd = root ? chroot_push(root) : -1; retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1, arg1); + free(root); chroot_pop(root_fd); #else /* HAVE_LUA */ - fprintf(stderr, "lua not available to run script\n"); + razor_set_error(error, RAZOR_GENERAL_ERROR, RAZOR_GENERAL_ERROR_FAILED, + name, "lua not available to run script"); retval = -1; #endif /* HAVE_LUA */ @@ -949,12 +992,12 @@ } static int -run_script_external(const char *root, const char *program, const char *script, - int arg1) +run_script_external(const char *root_uri, const char *program, + const char *script, int arg1, struct razor_error **error) { int root_fd, retval; FILE *fp; - char buf[32], *command; + char buf[32], *command, *root; if (program == NULL) { #if MSWIN_API @@ -971,7 +1014,11 @@ #endif } + root = razor_path_from_uri(root_uri, error); + if (!root) + return -1; root_fd = chroot_push(root); + free(root); if (arg1 >= 0) { sprintf(buf, "%d", arg1); command = malloc(strlen(program) + strlen(buf) + 2); @@ -982,10 +1029,11 @@ free(command); if (!fp) { - perror(program); + razor_set_error_posix(error, program); retval = -1; } else if (script && fwrite(script, strlen(script), 1, fp) != 1) { - perror("failed to write script to program"); + razor_set_error_posix(error, + "failed to write script to program"); retval = -1; } else retval = 0; @@ -998,8 +1046,8 @@ } static int -run_script(struct installer *installer, - unsigned int program_tag, unsigned int script_tag, int arg1) +run_script(struct installer *installer, unsigned int program_tag, + unsigned int script_tag, int arg1, struct razor_error **error) { int i, retval; struct razor_rpm *rpm = installer->rpm; @@ -1024,11 +1072,11 @@ } if (program && strcmp(program, "") == 0) - retval = run_script_lua(installer->root, script_tag, script, - arg1); + retval = run_script_lua(installer->root_uri, script_tag, + script, arg1, error); else - retval = run_script_external(installer->root, program, script, - arg1); + retval = run_script_external(installer->root_uri, program, + script, arg1, error); if (rpm->relocations) { environment_unset(&env); @@ -1040,7 +1088,8 @@ int razor_run_script(const char *root, enum razor_property_flags script, - const char *program, const char *body, int arg1) + const char *program, const char *body, int arg1, + struct razor_error **error) { int retval; unsigned int script_tag; @@ -1071,10 +1120,10 @@ script_tag = 0; break; } - retval = run_script_lua(root, script_tag, body, arg1); + retval = run_script_lua(root, script_tag, body, arg1, error); } else - retval = run_script_external(root, program, body, arg1); + retval = run_script_external(root, program, body, arg1, error); return retval; } @@ -1164,30 +1213,38 @@ RAZOR_EXPORT int razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic, - const char *root, int install_count, + const char *root_uri, int install_count, enum razor_stage_type stage) { struct installer installer; struct cpio_file_header *header; - struct stat buf; unsigned int mode; const char *path; size_t filesize; char *s; - int retval = 0, code; + int retval = 0, domain, code; + struct razor_error *tmp_error = NULL; assert (rpm != NULL); - assert (root != NULL); + assert (root_uri != NULL); installer.rpm = rpm; - installer.root = root; + installer.root_uri = root_uri; installer.atomic = atomic; /* FIXME: Only do this before a transaction, not per rpm. */ - if (*root && ((retval = stat(root, &buf)) || !S_ISDIR(buf.st_mode))) { - code = retval ? errno : ENOTDIR; - s = razor_concat(root, ": Directory does not exist", NULL); - razor_atomic_abort(atomic, RAZOR_POSIX_ERROR, code, s); + if (*root_uri && razor_uri_is_directory(root_uri, &tmp_error) <= 0) { + if (tmp_error) { + domain = razor_error_get_domain(tmp_error); + code = razor_error_get_code(tmp_error); + razor_error_free(tmp_error); + tmp_error = NULL; + } else { + domain = RAZOR_POSIX_ERROR; + code = ENOTDIR; + } + s = razor_concat(root_uri, ": Directory does not exist", NULL); + razor_atomic_abort(atomic, domain, code, s); free(s); return -1; } @@ -1195,9 +1252,14 @@ if (rpm->relocations) razor_relocations_set_rpm(rpm->relocations, rpm); - if (stage & RAZOR_STAGE_SCRIPTS_PRE) + if (stage & RAZOR_STAGE_SCRIPTS_PRE) { retval = run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN, - install_count); + install_count, &tmp_error); + if (retval) { + razor_atomic_propagate_error(atomic, tmp_error, NULL); + tmp_error = NULL; + } + } if (!retval && (stage & RAZOR_STAGE_FILES)) { if (installer_init(&installer)) @@ -1244,9 +1306,14 @@ retval = razor_atomic_in_error_state(atomic); } - if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) + if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) { retval = run_script(&installer, RPMTAG_POSTINPROG, - RPMTAG_POSTIN, install_count); + RPMTAG_POSTIN, install_count, &tmp_error); + if (retval) { + razor_atomic_propagate_error(atomic, tmp_error, NULL); + tmp_error = NULL; + } + } return retval; } @@ -1260,7 +1327,7 @@ free(rpm->dirs); free(rpm->prefixes); - err = razor_file_free_contents(rpm->map, rpm->size); + err = razor_uri_free_contents(rpm->map, rpm->size); free(rpm->evr); free(rpm); diff -r 7442b30ecaae -r 008c75a5e08d librazor/test-lua.c --- a/librazor/test-lua.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/test-lua.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 J. Ali Harlow + * Copyright (C) 2009, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,8 +22,6 @@ #include #include #include -#include -#include #include #include #include @@ -63,18 +61,19 @@ int r; void *script; size_t len; - char *s, *test_file, *srcdir; + char *s, *test_uri, *srcdir, *suffix, *cwd; FILE *fp; struct razor_error *error = NULL; + struct razor_uri base_ru, test_ru, ru; if (argc > 2) { - fprintf(stderr, "usage: %s [TESTS-FILE]\n", argv[0]); + fprintf(stderr, "usage: %s [TESTS-URI]\n", argv[0]); exit(1); } if (argc == 2) - test_file = argv[1]; + test_uri = argv[1]; else - test_file = "test.lua"; + test_uri = "test.lua"; if (!mkdtemp(root)) { perror(root); @@ -95,31 +94,68 @@ chmod(s, S_IRUSR | S_IWUSR | S_IXUSR); free(s); - script = razor_file_get_contents(test_file, &len, 0, &error); + for (len = 32;; len *= 2) { + cwd = malloc(len); + if (getcwd(cwd, len)) + break; + free(cwd); + } + cwd = realloc(cwd, strlen(cwd) + 1); + + s = razor_concat("file:", cwd, NULL); + if (razor_uri_parse(&test_ru, test_uri, &error) || + razor_uri_parse(&base_ru, s, &error)) { + fprintf(stderr, "%s\n", razor_error_get_msg(error)); + razor_error_free(error); + exit(1); + } + free(s); + + razor_uri_resolve(&ru, &base_ru, &test_ru); + razor_uri_destroy(&base_ru); + s = razor_uri_recompose(&ru); + razor_uri_destroy(&ru); + script = razor_uri_get_contents(s, &len, 0, &error); + free(s); if (!script) { srcdir = getenv("srcdir"); - if (srcdir && errno == ENOENT && *test_file != '/') { + if (srcdir && errno == ENOENT) { razor_error_free(error); - s = malloc(strlen(srcdir) + strlen(test_file) + 2); - strcpy(s, srcdir); - strcat(s, "/"); - strcat(s, test_file); - script = razor_file_get_contents(s, &len, 0, &error); - if (!script) { + error = NULL; + suffix = srcdir[strlen(srcdir) - 1] == '/' ? NULL : "/"; + if (*srcdir == '/') + s = razor_concat("file:", srcdir, suffix, NULL); + else + s = razor_concat("file:", cwd, "/", srcdir, + suffix, NULL); + razor_uri_parse(&base_ru, s, &error); + free(s); + if (!error) { + razor_uri_resolve(&ru, &base_ru, &test_ru); + razor_uri_destroy(&base_ru); + s = razor_uri_recompose(&ru); + razor_uri_destroy(&ru); + script = razor_uri_get_contents(s, &len, 0, + &error); + free(s); + } + if (error) { fprintf(stderr, "%s\n", razor_error_get_msg(error)); razor_error_free(error); exit(1); } - free(s); } else { fprintf(stderr, "%s\n", razor_error_get_msg(error)); razor_error_free(error); exit(1); } } - r = run_lua_script(root, test_file, script, len, -1); - razor_file_free_contents(script, len); + razor_uri_destroy(&test_ru); + free(cwd); + + r = run_lua_script(root, test_uri, script, len, -1); + razor_uri_free_contents(script, len); recursive_remove(root); exit(r ? 1 : 0); diff -r 7442b30ecaae -r 008c75a5e08d librazor/test-pfu.c --- a/librazor/test-pfu.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/test-pfu.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 J. Ali Harlow + * Copyright (C) 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,17 +26,18 @@ #endif #include "razor.h" -int is_ascii_letter(char c) +#ifdef MSWIN_API +static int is_ascii_letter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -int is_slash(char c) +static int is_slash(char c) { return c == '/' || c == '\\'; } -const char *mswin_path(const char *path) +static const char *mswin_path(const char *path) { if (path == NULL) return NULL; @@ -47,8 +48,9 @@ return path; } +#endif -int path_cmp(const char *p1, const char *p2) +static int path_cmp(const char *p1, const char *p2) { #ifdef MSWIN_API while(*p1 && *p2) { @@ -65,12 +67,13 @@ #endif } -int test_pfu(const char *url, const char *path) +static int test_pfu(const char *uri, const char *path) { char *s; int r; + struct razor_error *error = NULL; - s = razor_path_from_url(url); + s = razor_path_from_uri(uri, &error); #ifdef MSWIN_API path = mswin_path(path); @@ -82,18 +85,21 @@ r = (s != path); if (r) { - fprintf(stderr, "Fail: razor_path_from_url(\"%s\")", url); + fprintf(stderr, "Fail: razor_path_from_uri(\"%s\")", uri); if (s) fprintf(stderr, " returns \"%s\", expected", s); else - fprintf(stderr, " returns NULL, expected"); + fprintf(stderr, " fails (%s), expected", + razor_error_get_msg(error)); if (path) fprintf(stderr, " \"%s\"\n", path); else - fprintf(stderr, " NULL\n"); + fprintf(stderr, " failure\n"); } free(s); + if (error) + razor_error_free(error); return r; } @@ -101,7 +107,7 @@ #ifdef MSWIN_API UINT saved_cp; -void cleanup_on_exit(void) +static void cleanup_on_exit(void) { SetConsoleOutputCP(saved_cp); } diff -r 7442b30ecaae -r 008c75a5e08d librazor/test-uri.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librazor/test-uri.c Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2016 J. Ali Harlow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include "razor.h" +#include "razor-internal.h" + +static int test_parse(const char *uri) +{ + struct razor_uri ru; + struct razor_error *error = NULL; + int r; + + r = razor_uri_parse(&ru, uri, &error); + razor_uri_destroy(&ru); + + if (r < 0) { + fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n", + uri, razor_error_get_msg(error)); + return -1; + } + + return r; +} + +static int test_normalize(const char *uri, const char *expected_normalized_uri) +{ + struct razor_uri ru; + struct razor_error *error = NULL; + int r; + char *normalized_uri; + + r = razor_uri_parse(&ru, uri, &error); + + if (r < 0) { + razor_uri_destroy(&ru); + fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n", + uri, razor_error_get_msg(error)); + return -1; + } + + razor_uri_normalize(&ru); + normalized_uri = razor_uri_recompose(&ru); + razor_uri_destroy(&ru); + + if (strcmp(normalized_uri, expected_normalized_uri)) { + fprintf(stderr, "Fail: normalization of \"%s\" produces " + "\"%s\", expected \"%s\"\n", uri, normalized_uri, + expected_normalized_uri); + r = -1; + } + + free(normalized_uri); + return r; +} + +static int test_resolve(const char *base_uri, const char *relative_reference, + const char *expected_target_uri) +{ + struct razor_uri base_ru, rr_ru, target_ru; + struct razor_error *error = NULL; + char *target_uri; + int r; + + r = razor_uri_parse(&base_ru, base_uri, &error); + + if (r < 0) { + fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n", + base_uri, razor_error_get_msg(error)); + return -1; + } + + r = razor_uri_parse(&rr_ru, relative_reference, &error); + + if (r < 0) { + fprintf(stderr, "Fail: razor_uri_parse(\"%s\") reports %s\n", + relative_reference, razor_error_get_msg(error)); + razor_uri_destroy(&base_ru); + return -1; + } + + razor_uri_resolve(&target_ru, &base_ru, &rr_ru); + razor_uri_destroy(&base_ru); + razor_uri_destroy(&rr_ru); + + target_uri = razor_uri_recompose(&target_ru); + razor_uri_destroy(&target_ru); + + if (strcmp(target_uri, expected_target_uri)) { + fprintf(stderr, + "Fail: razor_uri_resolve(\"%s\", \"%s\") returns %s\n", + base_uri, relative_reference, target_uri); + free(target_uri); + return -1; + } + + free(target_uri); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int r = 0; + + r |= test_parse("file:"); + r |= test_parse("file:/"); + r |= test_parse("file:///"); + + /* From RFC 3986 § 6.2.2 */ + r |= test_normalize("eXAMPLE://a/./b/../b/%63/%7bfoo%7d", + "example://a/b/c/%7Bfoo%7D"); + + /* From RFC 3986 § 5.4.1 */ + r |= test_resolve("http://a/b/c/d;p?q", "g:h", "g:h"); + r |= test_resolve("http://a/b/c/d;p?q", "g", "http://a/b/c/g"); + r |= test_resolve("http://a/b/c/d;p?q", "./g", "http://a/b/c/g"); + r |= test_resolve("http://a/b/c/d;p?q", "g/", "http://a/b/c/g/"); + r |= test_resolve("http://a/b/c/d;p?q", "/g", "http://a/g"); + r |= test_resolve("http://a/b/c/d;p?q", "//g", "http://g"); + r |= test_resolve("http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y"); + r |= test_resolve("http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y"); + r |= test_resolve("http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s"); + r |= test_resolve("http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s"); + r |= test_resolve("http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s"); + r |= test_resolve("http://a/b/c/d;p?q", ";x", "http://a/b/c/;x"); + r |= test_resolve("http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x"); + r |= test_resolve("http://a/b/c/d;p?q", "g;x?y#s", + "http://a/b/c/g;x?y#s"); + r |= test_resolve("http://a/b/c/d;p?q", "", "http://a/b/c/d;p?q"); + r |= test_resolve("http://a/b/c/d;p?q", ".", "http://a/b/c/"); + r |= test_resolve("http://a/b/c/d;p?q", "./", "http://a/b/c/"); + r |= test_resolve("http://a/b/c/d;p?q", "..", "http://a/b/"); + r |= test_resolve("http://a/b/c/d;p?q", "../", "http://a/b/"); + r |= test_resolve("http://a/b/c/d;p?q", "../g", "http://a/b/g"); + r |= test_resolve("http://a/b/c/d;p?q", "../..", "http://a/"); + r |= test_resolve("http://a/b/c/d;p?q", "../../", "http://a/"); + r |= test_resolve("http://a/b/c/d;p?q", "../../g", "http://a/g"); + + r |= test_resolve("http://a/b/c/d;p?q", "../../../g", "http://a/g"); + r |= test_resolve("http://a/b/c/d;p?q", "../../../../g", "http://a/g"); + + r |= test_resolve("http://a/b/c/d;p?q", "/./g", "http://a/g"); + r |= test_resolve("http://a/b/c/d;p?q", "/../g", "http://a/g"); + r |= test_resolve("http://a/b/c/d;p?q", "g.", "http://a/b/c/g."); + r |= test_resolve("http://a/b/c/d;p?q", ".g", "http://a/b/c/.g"); + r |= test_resolve("http://a/b/c/d;p?q", "g..", "http://a/b/c/g.."); + r |= test_resolve("http://a/b/c/d;p?q", "..g", "http://a/b/c/..g"); + + r |= test_resolve("http://a/b/c/d;p?q", "./../g", "http://a/b/g"); + r |= test_resolve("http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/"); + r |= test_resolve("http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h"); + r |= test_resolve("http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h"); + r |= test_resolve("http://a/b/c/d;p?q", "g;x=1/./y", + "http://a/b/c/g;x=1/y"); + r |= test_resolve("http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y"); + + r |= test_resolve("http://a/b/c/d;p?q", "g?y/./x", + "http://a/b/c/g?y/./x"); + r |= test_resolve("http://a/b/c/d;p?q", "g?y/../x", + "http://a/b/c/g?y/../x"); + r |= test_resolve("http://a/b/c/d;p?q", "g#s/./x", + "http://a/b/c/g#s/./x"); + r |= test_resolve("http://a/b/c/d;p?q", "g#s/../x", + "http://a/b/c/g#s/../x"); + + r |= test_resolve("http://a/b/c/d;p?q", "http:g", "http:g"); + + /* From http://www.w3.org/2000/10/swap/uripath.py */ + r |= test_resolve("foo:xyz", "bar:abc", "bar:abc"); + + r |= test_resolve("http://example/x/y/z", "../abc", + "http://example/x/abc"); + r |= test_resolve("http://example2/x/y/z", "http://example/x/abc", + "http://example/x/abc"); + r |= test_resolve("http://ex/x/y/z", "../r", "http://ex/x/r"); + // "http://ex/x/y/z", "../../r", "http://ex/r"); // DanC had this. + r |= test_resolve("http://ex/x/y", "q/r", "http://ex/x/q/r"); + r |= test_resolve("http://ex/x/y", "q/r#s", "http://ex/x/q/r#s"); + r |= test_resolve("http://ex/x/y", "q/r#s/t", "http://ex/x/q/r#s/t"); + r |= test_resolve("http://ex/x/y", "ftp://ex/x/q/r", "ftp://ex/x/q/r"); + r |= test_resolve("http://ex/x/y", "", "http://ex/x/y"); + r |= test_resolve("http://ex/x/y/", "", "http://ex/x/y/"); + r |= test_resolve("http://ex/x/y/pdq", "", "http://ex/x/y/pdq"); + r |= test_resolve("http://ex/x/y/", "z/", "http://ex/x/y/z/"); + r |= test_resolve("file:/swap/test/animal.rdf", "#Animal", + "file:/swap/test/animal.rdf#Animal"); + r |= test_resolve("file:/e/x/y/z", "../abc", "file:/e/x/abc"); + r |= test_resolve("file:/example2/x/y/z", "/example/x/abc", + "file:/example/x/abc"); + r |= test_resolve("file:/ex/x/y/z", "../r", "file:/ex/x/r"); + r |= test_resolve("file:/ex/x/y/z", "/r", "file:/r"); + r |= test_resolve("file:/ex/x/y", "q/r", "file:/ex/x/q/r"); + r |= test_resolve("file:/ex/x/y", "q/r#s", "file:/ex/x/q/r#s"); + r |= test_resolve("file:/ex/x/y", "q/r#", "file:/ex/x/q/r#"); + r |= test_resolve("file:/ex/x/y", "q/r#s/t", "file:/ex/x/q/r#s/t"); + r |= test_resolve("file:/ex/x/y", "ftp://ex/x/q/r", "ftp://ex/x/q/r"); + r |= test_resolve("file:/ex/x/y", "", "file:/ex/x/y"); + r |= test_resolve("file:/ex/x/y/", "", "file:/ex/x/y/"); + r |= test_resolve("file:/ex/x/y/pdq", "", "file:/ex/x/y/pdq"); + r |= test_resolve("file:/ex/x/y/", "z/", "file:/ex/x/y/z/"); + r |= test_resolve("file:/devel/WWW/2000/10/swap/test/reluri-1.n3", + "file://meetings.example.com/cal#m1", + "file://meetings.example.com/cal#m1"); + r |= test_resolve("file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3", + "file://meetings.example.com/cal#m1", + "file://meetings.example.com/cal#m1"); + r |= test_resolve("file:/some/dir/foo", "./#blort", + "file:/some/dir/#blort"); + r |= test_resolve("file:/some/dir/foo", "./#", "file:/some/dir/#"); + /* From Graham Klyne Thu, 20 Feb 2003 18:08:17 +0000 */ + r |= test_resolve("http://example/x/y%2Fz", "abc", + "http://example/x/abc"); + r |= test_resolve("http://example/x/y/z", "/x%2Fabc", + "http://example/x%2Fabc"); + r |= test_resolve("http://example/x/y%2Fz", "/x%2Fabc", + "http://example/x%2Fabc"); + r |= test_resolve("http://example/x%2Fy/z", "abc", + "http://example/x%2Fy/abc"); + /* Ryan Lee */ + r |= test_resolve("http://example/x/abc.efg", "./", + "http://example/x/"); + + exit(r ? 1 : 0); +} diff -r 7442b30ecaae -r 008c75a5e08d librazor/transaction.c --- a/librazor/transaction.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/transaction.c Mon Jul 04 10:48:18 2016 +0100 @@ -26,11 +26,7 @@ #include #include #include -#include -#include #include -#include -#include #include #include diff -r 7442b30ecaae -r 008c75a5e08d librazor/types/array.c --- a/librazor/types/array.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/types/array.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc + * Copyright (C) 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,42 +24,100 @@ #include "types.h" -void -array_init(struct array *array) +void array_init(struct array *array) { memset(array, 0, sizeof *array); } -void -array_release(struct array *array) +void array_release(struct array *array) { free(array->data); } -void * -array_add(struct array *array, int size) +int array_set_size(struct array *array, int size) { int alloc; - void *data, *p; + void *data; if (array->alloc > 0) alloc = array->alloc; + else if (size > 0) + alloc = 16; else - alloc = 16; + alloc = 0; - while (alloc < array->size + size) + while (alloc < size) alloc *= 2; - if (array->alloc < alloc) { + if (!alloc) { + free(array->data); + array->data = NULL; + array->alloc = 0; + } else if (array->alloc < alloc) { data = realloc(array->data, alloc); if (data == NULL) - return 0; + return -1; array->data = data; array->alloc = alloc; } - p = array->data + array->size; - array->size += size; + array->size = size; - return p; + return 0; } + +void *array_add(struct array *array, int size) +{ + if (array_set_size(array, array->size + size) < 0) + return NULL; + + return array->data + array->size - size; +} + +void ptr_array_add(struct array *ptr_array, void *data) +{ + void **ptr, **ptrend; + + ptrend = ptr_array->data + ptr_array->size; + for (ptr = ptr_array->data; ptr < ptrend; ptr++) + if (!*ptr) + break; + + if (ptr == ptrend) + ptr = array_add(ptr_array, sizeof *ptr); + + *ptr = data; +} + +int ptr_array_find(struct array *ptr_array, void *data) +{ + void **ptr, **ptrend; + + ptrend = ptr_array->data + ptr_array->size; + for (ptr = ptr_array->data; ptr < ptrend; ptr++) + if (*ptr == data) + return ptr - (void **)ptr_array->data; + + return -1; +} + +void ptr_array_remove_index(struct array *ptr_array, int indx) +{ + void **ptr, **ptrend; + + ptrend = ptr_array->data + ptr_array->size; + + ptr = (void **)ptr_array->data + indx; + if (ptr >= ptrend) + return; + *ptr = NULL; + + for (ptr = ptr_array->data; ptr < ptrend; ptr++) + if (*ptr) + break; + + if (ptr == ptrend) { + array_release(ptr_array); + array_init(ptr_array); + } +} diff -r 7442b30ecaae -r 008c75a5e08d librazor/types/types.h --- a/librazor/types/types.h Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/types/types.h Mon Jul 04 10:48:18 2016 +0100 @@ -35,7 +35,11 @@ void array_init(struct array *array); void array_release(struct array *array); +int array_set_size(struct array *array, int size); void *array_add(struct array *array, int size); +void ptr_array_add(struct array *ptr_array, void *data); +int ptr_array_find(struct array *ptr_array, void *data); +void ptr_array_remove_index(struct array *ptr_array, int indx); #define RAZOR_ENTRY_LAST 0x80 diff -r 7442b30ecaae -r 008c75a5e08d librazor/uri-io.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librazor/uri-io.c Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,1177 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg + * Copyright (C) 2008 Red Hat, Inc + * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef MSWIN_API +#include +#include +#endif +#if HAVE_SYS_MMAN_H +#include +#endif +#include + +#include "razor.h" +#include "types/types.h" +#include "razor-internal.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define strcmp0(s1, s2) ((s1) && (s2) ? strcmp(s1, s2) : \ + (s1) ? 1 : (s2) ? -1 : 0) + +#define OPEN_FILE_USED (1U<<0) +#define OPEN_FILE_MMAPPED (1U<<1) + +struct open_file { + void *addr; + size_t length; + uint32_t flags; +}; + +struct array open_files = { 0, }; + +void *razor_file_get_contents(const char *filename, size_t *length, int private, + struct razor_error **error) +{ + int fd; + struct stat st; + void *addr = NULL; + size_t nb; + ssize_t res; + struct open_file *of, *ofend; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + razor_set_error_posix(error, filename); + return NULL; + } + + if (fstat(fd, &st) < 0) { + razor_set_error_posix(error, filename); + close(fd); + return NULL; + } + + *length = st.st_size; + + ofend = open_files.data + open_files.size; + for (of = open_files.data; of < ofend; of++) + if (!(of->flags & OPEN_FILE_USED)) + break; + if (of == ofend) { + of = array_add(&open_files, sizeof *of); + of->flags = 0; + } + +#if HAVE_SYS_MMAN_H + if (!private) { + addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + addr = NULL; + else + of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED; + } +#endif /* HAVE_SYS_MMAN_H */ + if (!addr) { + addr = malloc(st.st_size); + if (addr) { + of->flags = OPEN_FILE_USED; + nb = 0; + while(nb < st.st_size) { + res = read(fd, addr + nb, st.st_size - nb); + if (res <= 0) { + razor_set_error_posix(error, filename); + free(addr); + addr = NULL; + break; + } + nb += res; + } + } else + razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, + "Not enough memory"); + } + close(fd); + + of->addr = addr; + of->length = st.st_size; + + return addr; +} + +int razor_file_free_contents(void *addr, size_t length) +{ +#if HAVE_SYS_MMAN_H + int mmapped; +#endif + struct open_file *of, *ofend; + + ofend = open_files.data + open_files.size; + for (of = open_files.data; of < ofend; of++) + if ((of->flags & OPEN_FILE_USED) && of->addr == addr) + break; + + if (of == ofend) + return -2; + + length = of->length; +#if HAVE_SYS_MMAN_H + mmapped = of->flags & OPEN_FILE_MMAPPED; +#endif + of->flags &= ~OPEN_FILE_USED; + + for (of = open_files.data; of < ofend; of++) + if (of->flags & OPEN_FILE_USED) + break; + + if (of == ofend) { + array_release(&open_files); + array_init(&open_files); + } + +#if HAVE_SYS_MMAN_H + if (mmapped) + return munmap(addr, length); +#endif + + free(addr); + return 0; +} + +int razor_file_mkdir(const char *path, mode_t mode, struct razor_error **error) +{ + int retval, code; + struct stat buf; + + retval = mkdir(path, mode); + + if (retval) { + /* + * Ignore the case of a pre-existing directory and give + * an explicit error message if there is something other + * than a directory already at path. + */ + code = errno; + if (code != EEXIST || stat(path, &buf)) + razor_set_error(error, RAZOR_POSIX_ERROR, code, path, + strerror(code)); + else if (!S_ISDIR(buf.st_mode)) + razor_set_error(error, RAZOR_POSIX_ERROR, code, path, + "Not a directory"); + } + + return retval; +} + +int razor_file_unlink(const char *path, struct razor_error **error) +{ + int retval; + + retval = unlink(path); + + if (retval) + razor_set_error_posix(error, path); + + return retval; +} + +int razor_file_open(const char *path, int flags, mode_t mode, + struct razor_error **error) +{ + int retval; + + retval = open(path, flags, mode); + + if (retval < 0) + razor_set_error_posix(error, path); + + return retval; +} + +int razor_file_move(const char *path, const char *dest, + struct razor_error **error) +{ + int retval = 0; + +#ifdef MSWIN_API + wchar_t *oldbuf, *newbuf; + const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; + + newbuf = razor_utf8_to_utf16(dest, -1); + oldbuf = razor_utf8_to_utf16(path, -1); + + /* + * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will + * cover every case we care about _except_ replacing an empty + * directory with a file. Calling RemoveDirectory() will deal + * with this case while having no effect in all other cases. + */ + (void)RemoveDirectoryW(newbuf); + + if (!MoveFileExW(oldbuf, newbuf, flags)) { + razor_set_error_mswin(error, newbuf, GetLastError()); + retval = -1; + } + + free(newbuf); + free(oldbuf); +#else + int code; + const char *object; + + if (rename(path, dest)) { + if (error) { + code = errno; + if (access(path, F_OK) < 0) + object = path; + else + object = dest; + razor_set_error(error, RAZOR_POSIX_ERROR, code, object, + strerror(code)); + } + retval = -1; + } +#endif + + return retval; +} + +#ifndef MSWIN_API +static char *absolute_path(const char *path) +{ + int len; + char *result, *subpath, *p, *s, *t; + + result = realpath(path, NULL); + + if (!result && errno == ENOENT) { + p = strdup(path); + s = strrchr(p, '/'); + + while (s) { + if (s == p) { + result = strdup("/"); + break; + } + + *s = '\0'; + subpath = realpath(p, NULL); + + if (subpath) { + *s = '/'; + len = strlen(subpath); + result = malloc(len + strlen(s) + 1); + memcpy(result, subpath, len); + strcpy(result + len, s); + free(subpath); + break; + } else if (errno != ENOENT) + break; + + t = strrchr(p, '/'); + *s = '/'; + s = t; + } + + if (!s) + result = realpath(".", NULL); + + free(p); + } + + return result; +} +#endif + +int razor_file_is_directory(const char *path, struct razor_error **error) +{ + struct stat st; + + if (stat(path, &st) < 0) { + razor_set_error_posix(error, path); + return -1; + } + + return !!S_ISDIR(st.st_mode); +} + +char *razor_file_mkdtemp_near(const char *path, const char *template, + struct razor_error **error) +{ + char *retval; + +#ifdef MSWIN_API + if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\' + && strchr(path+3,'\\')) { + /* We have a UNC path: \\servername\sharename... */ + const char *sharename, *root; + int disklen; + + sharename = strchr(path+3,'\\')+1; + root = strchr(sharename,'\\'); + if (root) + disklen = root - path; + else + disklen = strlen(path); + + retval = malloc(disklen + 1 + strlen(template) + 1); + memcpy(retval, path, disklen); + retval[disklen] = '\\'; + strcpy(retval + disklen + 1, template); + } else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') && + path[1]==':') { + retval = malloc(3 + strlen(template) + 1); + retval[0] = path[0]; + retval[1] = ':'; + retval[2] = '\\'; + strcpy(retval + 3, template); + } else { + DWORD n; + wchar_t *buf; + char *dir; + + n = GetCurrentDirectoryW(0, NULL); + buf = malloc(n * sizeof(wchar_t)); + + if (GetCurrentDirectoryW(n, buf)) { + dir = razor_utf16_to_utf8(buf, n - 1); + free(buf); + retval = razor_file_mkdtemp_near(dir, template, error); + free(dir); + return retval; + } else { + retval = malloc(3 + strlen(template) + 1); + retval[0] = 'C'; + retval[1] = ':'; + retval[2] = '\\'; + strcpy(retval + 3, template); + } + + free(buf); + } +#else + /* + * Find the mount point (assuming we can write to the + * whole filesystem). Otherwise stop at the first + * unwritable directory and take one step back. + */ + char *s, *abspath, saved; + int len, can_step_back = 0; + dev_t filesystem; + struct stat buf; + + abspath = absolute_path(path); + if (!abspath) { + razor_set_error_posix(error, path); + return NULL; + } + + if (stat(abspath, &buf) < 0) { + if (errno == ENOENT) + filesystem = 0; + else { + razor_set_error_posix(error, abspath); + free(abspath); + return NULL; + } + } else + filesystem = buf.st_dev; + + len = strlen(abspath); + while(len > 1 && (s = strrchr(abspath, '/'))) { + if (s == abspath) { + saved = s[1]; + s[1] = '\0'; + len = s + 1 - abspath; + } else { + s[0] = '\0'; + len = s - abspath; + } + + if (stat(abspath, &buf) < 0) { + if (errno == ENOENT) + continue; + else { + razor_set_error_posix(error, abspath); + free(abspath); + return NULL; + } + } else if (!filesystem) + filesystem = buf.st_dev; + + if (buf.st_dev != filesystem || access(abspath, W_OK)) { + if (can_step_back) { + if (s == abspath) + s[1] = saved; + else + s[0] = '/'; + } + len = strlen(abspath); + break; + } else + can_step_back = 1; + } + + if (len == 1) + len = 0; /* Avoid an unslightly double slash. */ + retval = malloc(len + 1 + strlen(template) + 1); + memcpy(retval, abspath, len); + retval[len] = '/'; + strcpy(retval + len + 1, template); + + free(abspath); +#endif + + if (!mkdtemp(retval)) { + int err = errno; + +#ifdef EACCES + if (err == EACCES) { + char *s = strdup(template); + +#ifndef MSWIN_API + if (stat(".", &buf) < 0) { + razor_set_error_posix(error, "."); + free(s); + free(retval); + return NULL; + } + if (buf.st_dev != filesystem) + /* + * Don't use a different filesystem. It will + * only fail later on (in rename) and cause + * an unhelpful error message (EXDEV). + */ + free(s); + else +#endif + if (mkdtemp(s)) { + free(retval); + retval = s; + return retval; + } else + free(s); + } +#endif + + razor_set_error(error, RAZOR_POSIX_ERROR, err, retval, + strerror(err)); + + free(retval); + retval = NULL; + } + + return retval; +} + +struct open_dir { + uint32_t flags; +#ifdef MSWIN_API + _WDIR *dp; + wchar_t *path2; +#else + DIR *dp; + char *path; +#endif +}; + +#define OPEN_DIR_USED (1U<<0) + +struct array open_dirs = { 0, }; + +void *razor_file_opendir(const char *path, struct razor_error **error) +{ + struct open_dir *od, *odend; + + odend = open_dirs.data + open_dirs.size; + for (od = open_dirs.data; od < odend; od++) + if (!(od->flags & OPEN_DIR_USED)) + break; + if (od == odend) { + od = array_add(&open_dirs, sizeof *od); + od->flags = 0; + } + +#ifdef MSWIN_API + od->path2 = razor_utf8_to_utf16(path, -1); + od->dp = _wopendir(od->path2); +#else + od->path = strdup(path); + od->dp = opendir(od->path); +#endif + + if (!od->dp) { +#ifdef MSWIN_API + razor_set_error_mswin(error, od->path2, GetLastError()); + free(od->path2); +#else + razor_set_error_posix(error, od->path); + free(od->path); +#endif + return NULL; + } + + od->flags = OPEN_DIR_USED; + return od; +} + +char *razor_file_readdir(void *dp, struct razor_error **error) +{ + struct open_dir *od = dp, *odend; +#ifdef MSWIN_API + struct _wdirent *dirp; + char *path; +#else + struct dirent *dirp; +#endif + + odend = open_dirs.data + open_dirs.size; + if (dp < open_dirs.data || od >= odend || !(od->flags & OPEN_DIR_USED)) + return (char *)-1; + + errno = 0; + +#ifdef MSWIN_API + while((dirp = _wreaddir(od->dp))) { + path = razor_utf16_to_utf8(dirp->d_name, -1); + if (strcmp(path, ".") && strcmp(path, "..")) + return path; + else + free(path); + } +#else + while((dirp = readdir(od->dp))) + if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) + return strdup(dirp->d_name); +#endif + + if (errno) { +#ifdef MSWIN_API + razor_set_error_mswin(error, od->path2, GetLastError()); +#else + razor_set_error_posix(error, od->path); +#endif + } + + return NULL; +} + +int razor_file_closedir(void *dp, struct razor_error **error) +{ + struct open_dir *od = dp, *odend; + int retval; + + odend = open_dirs.data + open_dirs.size; + if (dp < open_dirs.data || od >= odend || !(od->flags & OPEN_DIR_USED)) + return -2; + +#ifdef MSWIN_API + /* + * I can't find documentation to state that _wclosedir() + * returns -1 on failure, so be paranoid. + */ + retval = _wclosedir(od->dp) ? -1 : 0; +#else + retval = closedir(od->dp); +#endif + + if (retval) { +#ifdef MSWIN_API + razor_set_error_mswin(error, od->path2, GetLastError()); +#else + razor_set_error_posix(error, od->path); +#endif + } + +#ifdef MSWIN_API + free(od->path2); +#else + free(od->path); +#endif + + od->flags &= ~OPEN_DIR_USED; + + for (od = open_dirs.data; od < odend; od++) + if (od->flags & OPEN_DIR_USED) + break; + + if (od == odend) { + array_release(&open_dirs); + array_init(&open_dirs); + } + + return retval; +} + +struct razor_uri_vtable_entry { + struct razor_uri_vtable vtable; + char *scheme; + struct array open_files, open_directories; +}; + +static struct array razor_uri_vtable_entries; + +static struct razor_uri_vtable_entry * + razor_uri_get_vtable_entry(const char *scheme) +{ + struct razor_uri_vtable_entry *entry, *eend, *fallback = NULL; + + eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size; + for(entry = razor_uri_vtable_entries.data; entry < eend; entry++) { + if (!strcmp0(entry->scheme, scheme)) + return entry; + else if (!entry->scheme) + fallback = entry; + } + + return fallback; +} + +int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error) +{ + int retval; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return -1; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return -1; + } + + if (path) { + razor_uri_destroy(&ru); + retval = razor_file_mkdir(path, mode, error); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.mkdir) { + retval = -1; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else + retval = entry->vtable.mkdir(uri, mode, error); + } + + return retval; +} + +int razor_uri_unlink(const char *uri, struct razor_error **error) +{ + int retval; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return -1; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return -1; + } + + if (path) { + razor_uri_destroy(&ru); + retval = razor_file_unlink(path, error); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.unlink) { + retval = -1; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else + retval = entry->vtable.unlink(uri, error); + } + + return retval; +} + +int razor_uri_open(const char *uri, int flags, mode_t mode, + struct razor_error **error) +{ + int retval; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return -1; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return -1; + } + + if (path) { + razor_uri_destroy(&ru); + retval = razor_file_open(path, flags, mode, error); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.open) { + retval = -1; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else + retval = entry->vtable.open(uri, flags, mode, error); + } + + return retval; +} + +int razor_uri_move(const char *src_uri, const char *dst_uri, + struct razor_error **error) +{ + int retval; + char *src_path, *dst_path; + struct razor_uri src_ru, dst_ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&src_ru, src_uri, error) || + razor_uri_parse(&dst_ru, dst_uri, error)) + return -1; + + src_path = razor_path_from_parsed_uri(&src_ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!src_path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&src_ru); + return -1; + } + + dst_path = razor_path_from_parsed_uri(&dst_ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!dst_path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&dst_ru); + razor_uri_destroy(&src_ru); + free(src_path); + return -1; + } + + if (src_path && dst_path) + retval = razor_file_move(src_path, dst_path, error); + else { + if (!strcmp(src_ru.scheme, dst_ru.scheme)) + entry = razor_uri_get_vtable_entry(src_ru.scheme); + else + entry = NULL; + if (entry && entry->vtable.move) + retval = entry->vtable.move(src_uri, dst_uri, error); + else if (strcmp(src_ru.scheme, dst_ru.scheme)) { + retval = -1; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + dst_uri, "Cross-scheme URI move"); + } else { + retval = -1; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + src_path ? dst_uri : src_uri, + "No URI handler installed"); + } + } + + razor_uri_destroy(&src_ru); + razor_uri_destroy(&dst_ru); + free(src_path); + free(dst_path); + + return retval; +} + +void *razor_uri_get_contents(const char *uri, size_t *length, int private, + struct razor_error **error) +{ + void *retval; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return NULL; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return NULL; + } + + if (path) { + razor_uri_destroy(&ru); + retval = razor_file_get_contents(path, length, private, error); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.get_contents) { + retval = NULL; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else { + retval = entry->vtable.get_contents(uri, length, + private, error); + if (retval) + ptr_array_add(&entry->open_files, retval); + } + } + + return retval; +} + +int razor_uri_free_contents(void *addr, size_t length) +{ + int retval, of; + struct razor_uri_vtable_entry *entry, *eend; + + if (!addr) + return 0; + + retval = razor_file_free_contents(addr, length); + + if (retval != -2) + return retval; + + eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size; + for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) { + of = ptr_array_find(&entry->open_files, addr); + if (of >= 0) { + if (entry->vtable.free_contents) + retval = entry->vtable.free_contents(addr, + length); + ptr_array_remove_index(&entry->open_files, of); + break; + } + } + + return retval; +} + +int razor_uri_is_directory(const char *uri, struct razor_error **error) +{ + int retval; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return -1; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return -1; + } + + if (path) { + razor_uri_destroy(&ru); + retval = razor_file_is_directory(path, error); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.is_directory) { + retval = -1; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else + retval = entry->vtable.is_directory(uri, error); + } + + return retval; +} + +char *razor_uri_mkdtemp_near(const char *uri, const char *template, + struct razor_error **error) +{ + char *retval, *s; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return NULL; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return NULL; + } + + if (path) { + razor_uri_destroy(&ru); + s = razor_file_mkdtemp_near(path, template, error); + retval = razor_path_to_uri(s); + free(s); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.mkdtemp_near) { + retval = NULL; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else + retval = entry->vtable.mkdtemp_near(uri, template, + error); + } + + return retval; +} + +void *razor_uri_opendir(const char *uri, struct razor_error **error) +{ + void *retval; + char *path; + struct razor_uri ru; + struct razor_uri_vtable_entry *entry; + struct razor_error *tmp_error = NULL; + + if (razor_uri_parse(&ru, uri, error)) + return NULL; + + path = razor_path_from_parsed_uri(&ru, &tmp_error); + + if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI)) + razor_error_free(tmp_error); + else if (!path) { + razor_propagate_error(error, tmp_error, NULL); + razor_uri_destroy(&ru); + return NULL; + } + + if (path) { + razor_uri_destroy(&ru); + retval = razor_file_opendir(path, error); + free(path); + } else { + entry = razor_uri_get_vtable_entry(ru.scheme); + razor_uri_destroy(&ru); + if (!entry || !entry->vtable.opendir) { + retval = NULL; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, + uri, "No URI handler installed"); + } else { + retval = entry->vtable.opendir(uri, error); + if (retval) + ptr_array_add(&entry->open_directories, retval); + } + } + + return retval; +} + +char *razor_uri_readdir(void *dir, struct razor_error **error) +{ + int od; + char *retval; + struct razor_uri_vtable_entry *entry, *eend; + + retval = razor_file_readdir(dir, error); + + if (retval != (char *)-1) + return retval; + + eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size; + for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) { + od = ptr_array_find(&entry->open_directories, dir); + if (od >= 0) { + if (entry->vtable.readdir) + retval = entry->vtable.readdir(dir, error); + break; + } + } + + if (retval == (char *)-1) { + retval = NULL; + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_FAILED, NULL, + "Invalid directory handle"); + } + + return retval; +} + +int razor_uri_closedir(void *dir, struct razor_error **error) +{ + int od; + int retval; + struct razor_uri_vtable_entry *entry, *eend; + + retval = razor_file_closedir(dir, error); + + if (retval != -2) + return retval; + + eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size; + for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) { + od = ptr_array_find(&entry->open_directories, dir); + if (od >= 0) { + if (entry->vtable.closedir) + retval = entry->vtable.closedir(dir, error); + break; + } + } + + if (retval == -2) + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_FAILED, NULL, + "Invalid directory handle"); + + return retval; +} + +RAZOR_EXPORT int razor_uri_set_vtable(const char *scheme, + struct razor_uri_vtable *vtable, struct razor_error **error) +{ + struct razor_uri_vtable_entry *entry, *eend; + + if (!strcmp0(scheme, "file")) { + /* + * There's no fundamental reason why we couldn't support + * this, but it's a lot of work without any obvious need. + */ + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_FAILED, scheme, + "Can't override file scheme handler"); + return -1; + } + + if (vtable->structure_size < sizeof(struct razor_uri_vtable)) { + /* + * A future version of the API might add vfuncs to the + * table (which we ignore), but won't remove any. + */ + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_FAILED, scheme, + "Invalid vtable structure size"); + return -1; + } + + eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size; + for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) { + if (!strcmp0(entry->scheme, scheme)) + break; + } + + if (entry == eend) { + if (!vtable) + return 0; + entry = array_add(&razor_uri_vtable_entries, sizeof *entry); + entry->scheme = scheme ? strdup(scheme) : NULL; + array_init(&entry->open_files); + array_init(&entry->open_directories); + } else if (entry->open_files.size || entry->open_directories.size) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_FAILED, scheme, + "URI handler busy"); + return -1; + } + + if (vtable) { + entry->vtable = *vtable; + entry->vtable.structure_size = sizeof(struct razor_uri_vtable); + } else { + free(entry->scheme); + if (entry + 1 < eend) + memmove(entry, entry + 1, eend - (entry + 1)); + array_set_size(&razor_uri_vtable_entries, + razor_uri_vtable_entries.size - sizeof *entry); + } + + return 0; +} diff -r 7442b30ecaae -r 008c75a5e08d librazor/uri.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librazor/uri.c Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,957 @@ +/* + * Copyright (C) 2016 J. Ali Harlow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#undef DEBUG + +#include +#include +#include "razor.h" +#include "types/types.h" +#include "razor-internal.h" +#include "uri.h" + +/* + * Following RFC 3986 § 3. + * Note that we don't validate queries or fragments. + */ + +#define strdup0(s) ((s) ? strdup(s) : NULL) + +#define string_str(str) ((char *)(str)->data) + +#define string_init(str) do { \ + char *_p; \ + array_init(str); \ + _p = array_add(str, 1); \ + *_p = '\0'; \ + } while(0) + +#define string_append_len(str, s, len) do { \ + char *_p; \ + _p = array_add(str, len); \ + _p--; \ + strncpy(_p, s, len); \ + _p[(len)] = '\0'; \ + } while(0) + +#define string_append(str, s) string_append_len(str, s, strlen(s)) + +#define string_truncate_at(str, s) do { \ + int _len; \ + _len = (s) - \ + (char *)(str)->data; \ + *(s) = '\0'; \ + (str)->size = _len + 1; \ + } while(0) + + +static const char *skip_uri_scheme(const char *uri) +{ + /* + * RFC 3986 defines scheme as: + * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + */ + if (*uri >= 'a' && *uri <= 'z' || *uri >= 'A' && *uri <= 'Z') { + do { + uri++; + } while (is_alnum(*uri) || *uri == '+' || *uri == '-' || + *uri == '.'); + if (*uri == ':') + return uri; + } + return NULL; +} + +static char *razor_strndup(const char *s, size_t n) +{ + char *result; + + if (memchr(s, '\0', n)) + result = strdup(s); + else { + result = malloc(n + 1); + memcpy(result, s, n); + result[n] = '\0'; + } + + return result; +} + +#if 0 +/* + * Return the (possibly decoded) pchar or 0 on end-of-string or -1 on error + */ +static int pchar_get_char_validated(const char *p) +{ + int c; + + if (p[0]=='\0') + c = 0; + else if (p[0]=='%') { + if (xdigit_value(p[1]) < 0) + return -1; + c = xdigit_value(p[1]) * 16; + if (xdigit_value(p[2]) < 0) + return -1; + c += xdigit_value(p[2]); + } else if (p[0] >= 'a' && p[0] <= 'z' || p[0] >= 'A' && p[0] <= 'Z' || + p[0] >= '0' && p[0] <= '9' || + strchr("-._~!$&'()*+,;=:@", p[0])) + c = p[0]; + else + c = -1; + + return c; +} +#endif + +/* + * Verify the percent encoding. All '%' characters must be followed by + * exactly two hexadecimal digits. + */ +static int pct_encoding_validate(const char *s) +{ + while (*s) { + if (*s == '%') { + if (xdigit_value(s[1]) < 0 || xdigit_value(s[2]) < 0) + return -1; + s += 2; + } + + s++; + } + + return 0; +} + +static char *pct_encoding_normalize(char *s) +{ + char *retval, *p; + int c; + + if (!s) + return NULL; + + p = retval = malloc(strlen(s) + 1); + + while (*s) { + if (*s == '%') { + c = pchar_get_char(s); + if (is_unreserved(c)) + *p++ = c; + else { + *p++ = '%'; + *p++ = "0123456789ABCDEF"[c/16]; + *p++ = "0123456789ABCDEF"[c%16]; + } + pchar_next_char(s); + } else + *p++ = *s++; + } + + *p++ = '\0'; + + return realloc(retval, p - retval); +} + +static int validate_userinfo(const char *userinfo, struct razor_error **error) +{ + const char *s; + + for (s = userinfo; *s; s++) { + if (!is_unreserved(*s) && *s != '%' && !is_sub_delim(*s) + && *s != ':') { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, userinfo, + "Invalid URI userinfo"); + return -1; + } + } + + return 0; +} + +static int validate_reg_name(const char *reg_name) +{ + const char *s; + + for (s = reg_name; *s; s++) { + if (!is_unreserved(*s) && *s != '%' && !is_sub_delim(*s)) + return -1; + } + + return 0; +} + +static int validate_ipv4address(const char *s, int length) +{ + int count = 0, digits, octet; + + for (;;) { + if (!length) + return -1; + + if (*s == '0') { + digits = 1; + octet = 0; + } else { + if (*s < '1' || *s > '9') + return -1; + + octet = *s - '0'; + + for (digits = 1; digits < length; digits++) { + if (s[digits] >= '0' && s[digits] <= '9') { + octet *= 10; + octet += s[digits] - '0'; + if (octet > 255) + return -1; + } else + break; + } + } + + s += digits; + length -= digits; + + if (++count == 4) + break; + + if (length < 1 || *s != '.') + return -1; + + s++; + length--; + } + + return length ? -1 : 0; +} + +static int count_ipv6_pieces(const char **s, int *length) +{ + int count, digits; + + for (digits = 0; digits < 4 && digits < *length; digits++) { + if (!is_xdigit((*s)[digits])) + break; + } + + if (!digits) + return 0; + + (*s) += digits; + (*length) -= digits; + count = 1; + + if (*length && **s == ':') { + (*s)++; + (*length)--; + count += count_ipv6_pieces(s, length); + if (count == 1) { + (*s)--; + (*length)++; + } + } + + return count; +} + +static int validate_ip_literal(const char *ip_literal, int length) +{ + const char *s, *dot; + int len, no_pieces, elide; + + if (length >= 4 && ip_literal[0] == 'v') { + /* IPvFuture */ + dot = strchr(ip_literal + 2, '.'); + if (!dot || dot >= ip_literal + length) + return -1; + for (s = ip_literal + 1; s < dot; s++) { + if (!is_xdigit(*s)) + return -1; + } + for (s = dot + 1; s < ip_literal + length; s++) { + if (!is_unreserved(*s) && !is_sub_delim(*s) && *s != ':') + return -1; + } + } else { + /* IPv6address */ + s = ip_literal; + len = length; + no_pieces = count_ipv6_pieces(&s, &len); + + if (len > 1 && s[0] == ':' && s[1] == ':') { + s += 2; + len -= 2; + elide = 1; + no_pieces += count_ipv6_pieces(&s, &len); + } else + elide = 0; + + if (!validate_ipv4address(s, len)) + no_pieces += 2; + else if (len) + return -1; + + if (no_pieces > 8 || no_pieces == 8 && elide || no_pieces < 1) + return -1; + } + + return 0; +} + +static int validate_host(const char *host, struct razor_error **error) +{ + int retval; + + if (host[0] == '[' && host[strlen(host) - 1] == ']') + retval = validate_ip_literal(host + 1, strlen(host) - 2); + else { + retval = validate_ipv4address(host, strlen(host)); + if (retval < 0) + retval = validate_reg_name(host); + } + + if (retval) + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, host, + "Invalid URI host"); + + return retval; +} + +static char *strdown(char *s) +{ + while (*s) { + if (*s >= 'A' && *s <= 'Z') { + *s -= 'A'; + *s += 'a'; + } + s++; + } + + return s; +} + +static int razor_uri_parse_authority(struct razor_uri *ru, + const char *authority, int length, + struct razor_error **error) +{ + const char *s, *auth = authority; + char *userinfo, *port, *host; + + s = strchr(auth, '@'); + if (s && s < auth + length) { + userinfo = razor_strndup(auth, s - auth); + s++; + length -= s - auth; + auth = s; + + if (validate_userinfo(userinfo, error)) { + free(userinfo); + return -1; + } + } else + userinfo = NULL; + + s = strchr(auth, ':'); + if (s && s < auth + length) { + s++; + port = razor_strndup(s, length - (s - auth)); + s--; + length = s - auth; + + if (strspn(port, "0123456789") != strlen(port)) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, port, + "Invalid URI port"); + free(userinfo); + free(port); + return -1; + } + } else + port = NULL; + + host = razor_strndup(auth, length); + + if (validate_host(host, error)) { + free(userinfo); + free(port); + free(host); + return -1; + } + + ru->userinfo = userinfo; + ru->port = port; + ru->host = host; + + return 0; +} + +/* + * Parse either a hier-part or a relative-part + */ +static int razor_uri_parse_part(struct razor_uri *ru, const char *part, + int relative_part, struct razor_error **error) +{ + const char *s, *hp = part; + char *path, *p; + int noscheme = 0; + + if (hp[0] == '/' && hp[1] == '/') { + hp += 2; + s = strpbrk(hp, "/?#"); + if (!s) + s = hp + strlen(hp); + if (razor_uri_parse_authority(ru, hp, s - hp, error) < 0) + return -1; + hp = s; + } else { + ru->userinfo = NULL; + ru->host = NULL; + ru->port = NULL; + } + + if (!*hp) { + /* path-empty */ + ru->path = strdup(""); + return 0; + } else if (*hp == '/') { + /* path-absolute */ + p = path = malloc(strlen(hp) + 1); + *p++ = '/'; + hp++; + if (!*hp) { + *p++ = '\0'; + ru->path = realloc(path, p - path); + return 0; + } + } else if (!ru->host) { + /* path-rootless or path-noscheme */ + noscheme = relative_part; + p = path = malloc(strlen(hp) + 1); + } else { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, part, + relative_part ? "Invalid URI relative part" : + "Invalid URI hierarchical part"); + return -1; + } + + if (!is_pchar(*hp) || noscheme && *hp == ':') { + free(path); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, part, + "Invalid character in URI path"); + return -1; + } + *p++ = *hp++; + + while (*hp) { + if (*hp == '/') + noscheme = 0; + else if (!is_pchar(*hp) || noscheme && *hp == ':') { + free(path); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, part, + "Invalid character in URI path"); + return -1; + } + *p++ = *hp++; + } + + *p++ = '\0'; + + ru->path = realloc(path, p - path); + + return 0; +} + +void razor_uri_destroy(struct razor_uri *ru) +{ + free(ru->scheme); + free(ru->userinfo); + free(ru->host); + free(ru->port); + free(ru->path); + free(ru->query); + free(ru->fragment); +} + +int razor_uri_parse_uri(struct razor_uri *ru, const char *uri, int absolute, + struct razor_error **error) +{ + int r; + const char *s; + char *hier_part; + + if (pct_encoding_validate(uri) < 0) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, uri, + "Invalid percent encoding"); + return -1; + } + + memset(ru, 0, sizeof(*ru)); + + s = skip_uri_scheme(uri); + if (!s) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, uri, + "Invalid URI scheme"); + return -1; + } + ru->scheme = razor_strndup(uri, s - uri); + uri = s + 1; + + s = strchr(uri, '?'); + if (!s) + s = strchr(uri, '#'); + if (!s) + s = uri + strlen(uri); + hier_part = razor_strndup(uri, s - uri); + uri = s; + + r = razor_uri_parse_part(ru, hier_part, 0, error); + free(hier_part); + if (r) { + razor_uri_destroy(ru); + return -1; + } + + if (*uri != '?') + ru->query = NULL; + else { + uri++; + s = strchr(uri, '#'); + if (!s) + s = uri + strlen(uri); + ru->query = razor_strndup(uri, s - uri); + uri = s; + } + + if (*uri != '#') + ru->fragment = NULL; + else if (absolute) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, uri, + "Fragments are not allowed in absolute URIs"); + razor_uri_destroy(ru); + return -1; + } else { + uri++; + ru->fragment = strdup(uri); + } + + return 0; +} + +int razor_uri_parse_relative_ref(struct razor_uri *ru, const char *uri, + struct razor_error **error) +{ + int r; + const char *s; + char *relative_part; + + if (pct_encoding_validate(uri) < 0) { + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, uri, + "Invalid percent encoding"); + return -1; + } + + memset(ru, 0, sizeof(*ru)); + + s = strchr(uri, '?'); + if (!s) + s = strchr(uri, '#'); + if (!s) + s = uri + strlen(uri); + relative_part = razor_strndup(uri, s - uri); + uri = s; + + r = razor_uri_parse_part(ru, relative_part, 1, error); + free(relative_part); + if (r) + return -1; + + if (*uri == '?') { + uri++; + s = strchr(uri, '#'); + if (!s) + s = uri + strlen(uri); + ru->query = razor_strndup(uri, s - uri); + uri = s; + } else + ru->query = NULL; + + if (*uri == '#') { + uri++; + ru->fragment = strdup(uri); + } else + ru->fragment = NULL; + + return 0; +} + +int razor_uri_parse(struct razor_uri *ru, const char *uri, + struct razor_error **error) +{ + struct razor_error *tmp_error = NULL; + int r; + + r = razor_uri_parse_uri(ru, uri, 0, &tmp_error); + if (r < 0) { + r = razor_uri_parse_relative_ref(ru, uri, NULL); + if (r < 0) + razor_propagate_error(error, tmp_error, NULL); + else + razor_error_free(tmp_error); + } + + return r; +} + +/* + * Following RFC 3986 § 5.2.4 + */ +static char *remove_dot_segments(const char *path) +{ + struct array output; + char *input, *in, *s, *t; + const char *step; + +#ifdef DEBUG + fprintf(stderr, "STEP OUTPUT BUFFER INPUT BUFFER\n"); +#endif + + input = strdup(path); + in = input; + string_init(&output); + +#ifdef DEBUG + fprintf(stderr, " 1 : %-21s %s\n", string_str(&output), in); +#endif + + while (*in) { + if (str_has_prefix(in, "../")) { + step = "2A"; + in += 3; + } else if (str_has_prefix(in, "./")) { + step = "2A"; + in += 2; + } else if (str_has_prefix(in, "/./")) { + step = "2B"; + in += 2; + } else if (!strcmp(in, "/.")) { + step = "2B"; + in++; + *in = '/'; + } else if (str_has_prefix(in, "/../")) { + step = "2C"; + in += 3; + s = strrchr(string_str(&output), '/'); + if (!s) + s = string_str(&output); + string_truncate_at(&output, s); + } else if (!strcmp(in, "/..")) { + step = "2C"; + in += 2; + *in = '/'; + s = strrchr(string_str(&output), '/'); + if (!s) + s = string_str(&output); + string_truncate_at(&output, s); + } else if (!strcmp(in, ".") || !strcmp(in, "..")) { + step = "2D"; + in += strlen(in); + } else { + step = "2E"; + t = strchr(in + 1, '/'); + if (!t) + t = in + strlen(in); + string_append_len(&output, in, t - in); + in = t; + } +#ifdef DEBUG + fprintf(stderr, " %s: %-21s %s\n", step, string_str(&output), + in); +#endif + } + + free(input); + return string_str(&output); +} + + +/* + * Following RFC 3986 § 6.2.2 + */ +void razor_uri_normalize(struct razor_uri *ru) +{ + char *s; + + strdown(ru->scheme); + if (ru->host) + strdown(ru->host); + + s = pct_encoding_normalize(ru->userinfo); + free(ru->userinfo); + ru->userinfo = s; + + s = pct_encoding_normalize(ru->host); + free(ru->host); + ru->host = s; + + s = pct_encoding_normalize(ru->path); + free(ru->path); + ru->path = s; + + s = pct_encoding_normalize(ru->query); + free(ru->query); + ru->query = s; + + s = pct_encoding_normalize(ru->fragment); + free(ru->fragment); + ru->fragment = s; + + s = remove_dot_segments(ru->path); + free(ru->path); + ru->path = s; +} + +char *razor_uri_get_authority(const struct razor_uri *ru) +{ + char *result, *r; + int len = 1; + + if (ru->host) { + if (ru->userinfo) + len += strlen(ru->userinfo) + 1; + len += strlen(ru->host); + if (ru->port) + len += strlen(ru->port) + 1; + } else + return NULL; + + r = result = malloc(len); + + if (ru->userinfo) { + strcpy(r, ru->userinfo); + r += strlen(r); + *r++ = '@'; + } + + strcpy(r, ru->host); + r += strlen(r); + + if (ru->port) { + *r++ = ':'; + strcpy(r, ru->port); + } + + return result; +} + +/* + * Following RFC 3986 § 5.3 + */ +char *razor_uri_recompose(const struct razor_uri *ru) +{ + char *authority, *result, *r; + int len = 1; + + authority = razor_uri_get_authority(ru); + + if (ru->scheme) + len += strlen(ru->scheme) + 1; + if (authority) + len += strlen(authority) + 2; + len += strlen(ru->path); + if (ru->query) + len += strlen(ru->query) + 1; + if (ru->fragment) + len += strlen(ru->fragment) + 1; + + r = result = malloc(len); + + if (ru->scheme) { + strcpy(r, ru->scheme); + r += strlen(r); + *r++ = ':'; + } + + if (authority) { + *r++ = '/'; + *r++ = '/'; + strcpy(r, authority); + free(authority); + r += strlen(r); + } + + strcpy(r, ru->path); + r += strlen(r); + + if (ru->query) { + *r++ = '?'; + strcpy(r, ru->query); + r += strlen(r); + } + + if (ru->fragment) { + *r++ = '#'; + strcpy(r, ru->fragment); + } + + return result; +} + +/* + * Following RFC 3986 § 5.2.3 + */ +static char *merge_paths(const struct razor_uri *base,const struct razor_uri *R) +{ + char *s, *t, *path; + + if (base->host && !*base->path) + path = razor_concat("/", R->path, NULL); + else { + s = strrchr(base->path, '/'); + if (s) { + t = razor_strndup(base->path, s + 1 - base->path); + path = razor_concat(t, R->path, NULL); + free(t); + } else + path = strdup(R->path); + } + + return path; +} + +/* + * Following RFC 3986 § 5.2 + */ +void razor_uri_resolve(struct razor_uri *T, const struct razor_uri *base, + const struct razor_uri *R) +{ + char *s; + + if (R->scheme) { + T->scheme = strdup(R->scheme); + T->userinfo = strdup0(R->userinfo); + T->host = strdup0(R->host); + T->port = strdup0(R->port); + T->path = remove_dot_segments(R->path); + T->query = strdup0(R->query); + } else { + if (R->host) { + T->userinfo = strdup0(R->userinfo); + T->host = strdup0(R->host); + T->port = strdup0(R->port); + T->path = remove_dot_segments(R->path); + T->query = strdup0(R->query); + } else { + if (!*R->path) { + T->path = strdup(base->path); + if (R->query) + T->query = strdup(R->query); + else + T->query = strdup0(base->query); + } else { + if (*R->path == '/') + T->path = remove_dot_segments(R->path); + else { + s = merge_paths(base, R); + T->path = remove_dot_segments(s); + free(s); + } + T->query = strdup0(R->query); + } + T->userinfo = strdup0(base->userinfo); + T->host = strdup0(base->host); + T->port = strdup0(base->port); + } + T->scheme = strdup(base->scheme); + } + T->fragment = strdup0(R->fragment); +} + +/* + * This differs from razor_uri_resolve() both in the types of its arguments + * and in the fact that it takes a root URI rather than a base URI. The base + * URI is determined by appending a slash to the root URI (if it doesn't + * already end in a slash). Finally, uri can be explicitly marked as either + * relative (ie., a relative-ref) or not (ie., a URI). This is important as + * otherwise "c:/xxx" could be interpreted as a URI in the "c" scheme. + */ +char *razor_resolve_uri_root(const char *root_uri, const char *uri, + int is_relative, struct razor_error **error) +{ + int r; + char *base_uri, *s, *result; + struct razor_uri ru, base, file; + + if (!root_uri || !*root_uri) + root_uri = "file:/"; + + if (root_uri[strlen(root_uri) - 1] == '/') + base_uri = strdup(root_uri); + else + base_uri = razor_concat(root_uri, "/", NULL); + + r = razor_uri_parse_uri(&base, base_uri, 1, error); + free(base_uri); + if (r) + return NULL; + + if (is_relative > 0) { + /* + * We can't use razor_uri_parse_relative_ref() to parse + * uri in case it starts with a segment that includes a + * colon. Thus we use this kludge. + */ + s = razor_concat("scheme:", uri, NULL); + r = razor_uri_parse_uri(&file, s, 0, error); + free(s); + if (!r) { + free(file.scheme); + file.scheme = NULL; + } + } + else if (!is_relative) + r = razor_uri_parse_uri(&file, uri, 0, error); + else + r = razor_uri_parse(&file, uri, error); + if (r) { + razor_uri_destroy(&base); + return NULL; + } + + razor_uri_resolve(&ru, &base, &file); + + razor_uri_destroy(&base); + razor_uri_destroy(&file); + + result = razor_uri_recompose(&ru); + + razor_uri_destroy(&ru); + + return result; +} diff -r 7442b30ecaae -r 008c75a5e08d librazor/uri.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librazor/uri.h Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 J. Ali Harlow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define is_alpha(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') + +#define is_alnum(c) (is_alpha(c) || (c) >= '0' && (c) <= '9') + +#define is_xdigit(c) ((c) >= '0' && (c) <= '9' || \ + (c) >= 'a' && (c) <= 'f' || \ + (c) >= 'A' && (c) <= 'F') + +#define is_unreserved(c) (is_alnum(c) || (c) == '-' || (c) == '.' || \ + (c) == '_' || (c) == '~') + +#define is_sub_delim(c) strchr("!$&'()*+,;=", c) + +#define is_pchar(c) (is_unreserved(c) || (c) == '%' || \ + is_sub_delim(c) || (c) == ':' || (c) == '@') + +#define xdigit_value(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \ + (c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \ + (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : -1) + +#define pchar_get_char(p) ((p)[0] == '%' ? \ + xdigit_value((p)[1]) * 16 + xdigit_value((p)[2]) : \ + (p)[0]) + +#define pchar_next_char(p) \ + do { \ + if ((p)[0] == '%') \ + (p) += 3; \ + else \ + (p)++; \ + } while(0) + diff -r 7442b30ecaae -r 008c75a5e08d librazor/util.c --- a/librazor/util.c Sat Jun 11 17:56:48 2016 +0100 +++ b/librazor/util.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow + * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,32 +22,20 @@ #include #include -#include -#include #include #include #include #include #include -#include -#ifdef MSWIN_API -#include -#include -#else +#ifndef MSWIN_API #include #endif -#if HAVE_SYS_MMAN_H -#include -#endif #include #include "razor.h" +#include "types/types.h" #include "razor-internal.h" -#ifndef O_BINARY -#define O_BINARY 0 -#endif - /* Required by gnulib on non-libc platforms */ char *program_name = "librazor"; @@ -62,130 +50,6 @@ return p; } -#if HAVE_SYS_MMAN_H -#define OPEN_FILE_USED (1U<<0) -#define OPEN_FILE_MMAPPED (1U<<1) - -struct open_file { - void *addr; - size_t length; - uint32_t flags; -}; - -struct array open_files = { 0, }; -#endif /* HAVE_SYS_MMAN_H */ - -void * -razor_file_get_contents(const char *filename, size_t *length, int private, - struct razor_error **error) -{ - int fd; - struct stat st; - void *addr = NULL; - size_t nb; - ssize_t res; -#if HAVE_SYS_MMAN_H - struct open_file *of, *ofend; -#endif - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) { - razor_set_error_posix(error, filename); - return NULL; - } - - if (fstat(fd, &st) < 0) { - razor_set_error_posix(error, filename); - close(fd); - return NULL; - } - - *length = st.st_size; - -#if HAVE_SYS_MMAN_H - ofend = open_files.data + open_files.size; - for (of = open_files.data; of < ofend; of++) - if (!(of->flags & OPEN_FILE_USED)) - break; - if (of == ofend) { - of = array_add(&open_files, sizeof *of); - of->flags = 0; - } - - if (!private) { - addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (addr == MAP_FAILED) - addr = NULL; - else - of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED; - } -#endif /* HAVE_SYS_MMAN_H */ - if (!addr) { - addr = malloc(st.st_size); - if (addr) { -#if HAVE_SYS_MMAN_H - of->flags = OPEN_FILE_USED; -#endif - nb = 0; - while(nb < st.st_size) { - res = read(fd, addr + nb, st.st_size - nb); - if (res <= 0) { - razor_set_error_posix(error, filename); - free(addr); - addr = NULL; - break; - } - nb += res; - } - } else - razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, - "Not enough memory"); - } - close(fd); - -#if HAVE_SYS_MMAN_H - of->addr = addr; - of->length = st.st_size; -#endif - - return addr; -} - -int razor_file_free_contents(void *addr, size_t length) -{ -#if HAVE_SYS_MMAN_H - int retval, mmapped; - struct open_file *of, *ofend; - - ofend = open_files.data + open_files.size; - for (of = open_files.data; of < ofend; of++) - if ((of->flags & OPEN_FILE_USED) && of->addr == addr) - break; - - if (of == ofend) - return 1; - - length = of->length; - mmapped = of->flags & OPEN_FILE_MMAPPED; - of->flags &= ~OPEN_FILE_USED; - - for (of = open_files.data; of < ofend; of++) - if (of->flags & OPEN_FILE_USED) - break; - - if (of == ofend) { - array_release(&open_files); - array_init(&open_files); - } - - if (mmapped) - return munmap(addr, length); -#endif - - free(addr); - return 0; -} - struct qsort_context { size_t size; razor_compare_with_data_func_t compare; diff -r 7442b30ecaae -r 008c75a5e08d src/import-rpmdb.c --- a/src/import-rpmdb.c Sat Jun 11 17:56:48 2016 +0100 +++ b/src/import-rpmdb.c Mon Jul 04 10:48:18 2016 +0100 @@ -24,6 +24,10 @@ #include #include #include +/* + * Enable rpm 4.4 compatibility mode, see http://rpm.org/wiki/Releases/4.6.0 + */ +#define _RPM_4_4_COMPAT #include #include diff -r 7442b30ecaae -r 008c75a5e08d src/main.c --- a/src/main.c Sat Jun 11 17:56:48 2016 +0100 +++ b/src/main.c Mon Jul 04 10:48:18 2016 +0100 @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc - * Copyright (C) 2009, 2011-2012, 2014 J. Ali Harlow + * Copyright (C) 2009, 2011-2012, 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,7 +49,7 @@ static const char system_repo_filename[] = "system.rzdb"; static const char next_repo_filename[] = "system-next.rzdb"; -static const char rawhide_repo_filename[] = "rawhide.rzdb"; +static const char rawhide_repo_uri[] = "file:rawhide.rzdb"; static const char *install_root = ""; static const char *repo_filename = system_repo_filename; static const char *yum_url; @@ -150,7 +150,7 @@ opterr = 0; - opt = getopt_long(argc, argv, "+", longopts, NULL); + opt = getopt_long(argc, (char **)argv, "+", longopts, NULL); switch (opt) { @@ -621,13 +621,13 @@ FILE *wfp, *rfp; char buffer[256], *ptr, *local; size_t nb, n; + struct razor_error *error = NULL; - local = razor_path_from_url(url); + local = razor_path_from_uri(url, &error); if (local == NULL) { - fprintf(stderr, - "%s: download manually (curl not available)\n", - file); + fprintf(stderr, "%s: %s\n", file, razor_error_get_msg(error)); + razor_error_free(error); return -1; } else { rfp = fopen(local, "rb"); @@ -723,24 +723,12 @@ curl_easy_setopt(curl, CURLOPT_URL, url); res = curl_easy_perform(curl); fclose(fp); + putc('\n', stderr); if (res != CURLE_OK) { fprintf(stderr, "curl error: %s\n", error); unlink(file); return -1; } - res = curl_easy_getinfo(curl, - CURLINFO_RESPONSE_CODE, &response); - if (res != CURLE_OK) { - fprintf(stderr, "curl error: %s\n", error); - unlink(file); - return -1; - } - if (response != 200) { - fprintf(stderr, " - failed %ld\n", response); - unlink(file); - return -1; - } - fprintf(stderr, "\n"); curl_easy_cleanup(curl); return 0; @@ -799,13 +787,13 @@ if (set == NULL) return 1; atomic = razor_atomic_open("Yum import repository"); - razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL); + razor_set_write(set, atomic, rawhide_repo_uri, RAZOR_SECTION_ALL); retval = razor_atomic_commit(atomic); razor_set_unref(set); if (retval) fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic)); else - printf("wrote %s\n", rawhide_repo_filename); + printf("wrote %s\n", rawhide_repo_uri); razor_atomic_destroy(atomic); return retval; @@ -994,7 +982,7 @@ set = razor_root_open_read_only(install_root, &error); if (set) - updated = razor_set_open(rawhide_repo_filename, 0, &error); + updated = razor_set_open(rawhide_repo_uri, 0, &error); else updated = NULL; if (updated == NULL) { @@ -1131,7 +1119,9 @@ RAZOR_DETAIL_LAST); s = rpm_filename(name, version, arch); - url = razor_concat(yum_url, "/Packages/", s, NULL); + file = razor_concat("Packages/", s, NULL); + url = razor_path_relative_to_uri(yum_url, file, NULL); + free(file); file = razor_concat("rpms/", s, NULL); free(s); if (download_if_missing(url, file) < 0) @@ -1166,7 +1156,7 @@ const char *preunprog, *preun, *postunprog, *postun; const char *install_prefix; const char *const *prefixes; - char *file, *s; + char *file, *s, *uri, *filename; uint32_t flags; importer = razor_importer_create(); @@ -1185,14 +1175,20 @@ RAZOR_DETAIL_POSTUNPROG, &postunprog, RAZOR_DETAIL_POSTUN, &postun, RAZOR_DETAIL_LAST)) { - s = rpm_filename(name, version, arch); - file = razor_concat("rpms/", s, NULL); + filename = rpm_filename(name, version, arch); + s = razor_concat("Packages/", filename, NULL); + uri = razor_path_relative_to_uri(yum_url, s, NULL); free(s); - rpm = razor_rpm_open(file, &error); + file = razor_concat("rpms/", filename, NULL); + free(filename); + download_if_missing(uri, file); + free(uri); + uri = razor_path_to_uri(file); free(file); + rpm = razor_rpm_open(uri, &error); + free(uri); if (rpm == NULL) { razor_atomic_propagate_error(atomic, error, NULL); - razor_error_free(error); razor_package_iterator_destroy(pkg_iter); razor_importer_destroy(importer); return NULL; @@ -1249,7 +1245,7 @@ { int retval; const char *name, *version, *arch; - char *file, *s; + char *file, *s, *uri; struct razor_rpm *rpm; struct razor_error *error=NULL; @@ -1265,12 +1261,13 @@ s = rpm_filename(name, version, arch); file = razor_concat("rpms/", s, NULL); free(s); - rpm = razor_rpm_open(file, &error); + uri = razor_path_to_uri(file); free(file); + rpm = razor_rpm_open(uri, &error); + free(uri); if (rpm == NULL) { razor_atomic_propagate_error(atomic, error, NULL); fprintf(stderr, "%s\n", razor_error_get_msg(error)); - razor_error_free(error); return -1; } if (relocations) @@ -1441,7 +1438,7 @@ } } while (opt); - upstream = razor_set_open(rawhide_repo_filename, 0, &error); + upstream = razor_set_open(rawhide_repo_uri, 0, &error); if (upstream == NULL) { fprintf(stderr, "%s\n", razor_error_get_msg(error)); razor_error_free(error); @@ -1513,7 +1510,7 @@ } } - if (razor_atomic_create_dir(atomic, "rpms", + if (razor_atomic_create_dir(atomic, "file:rpms", S_IRWXU | S_IRWXG | S_IRWXO) || razor_atomic_commit(atomic)) { fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic)); @@ -1604,7 +1601,7 @@ struct razor_package_iterator *pi; struct razor_package *package; const char *pattern, *name, *version, *arch; - char url[256], file[256]; + char *url, *file, *s, filename[256]; int matches = 0; switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) { @@ -1621,7 +1618,7 @@ pattern = argv[optind]; - set = razor_set_open(rawhide_repo_filename, 0, &error); + set = razor_set_open(rawhide_repo_uri, 0, &error); if (set == NULL) { fprintf(stderr, "%s\n", razor_error_get_msg(error)); razor_error_free(error); @@ -1630,7 +1627,7 @@ atomic = razor_atomic_open("Download packages"); - if (razor_atomic_create_dir(atomic, "rpms", + if (razor_atomic_create_dir(atomic, "file:rpms", S_IRWXU | S_IRWXG | S_IRWXO)) { fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic)); razor_atomic_destroy(atomic); @@ -1654,12 +1651,15 @@ continue; matches++; - snprintf(url, sizeof url, - "%s/Packages/%s-%s.%s.rpm", - yum_url, name, version, arch); - snprintf(file, sizeof file, - "rpms/%s-%s.%s.rpm", name, version, arch); + snprintf(filename, sizeof filename, + "%s-%s.%s.rpm", name, version, arch); + s = razor_concat("Packages/", filename, NULL); + url = razor_path_relative_to_uri(yum_url, s, NULL); + free(s); + file = razor_concat("rpms/", filename, NULL); download_if_missing(url, file); + free(url); + free(file); } razor_package_iterator_destroy(pi); razor_set_unref(set); @@ -1804,7 +1804,7 @@ snprintf(pattern, sizeof pattern, "*%s*", argv[1]); - set = razor_set_open(rawhide_repo_filename, 0, &error); + set = razor_set_open(rawhide_repo_uri, 0, &error); if (set == NULL) { fprintf(stderr, "%s\n", razor_error_get_msg(error)); razor_error_free(error); @@ -1939,7 +1939,7 @@ while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) { switch (opt) { case opt_database: - razor_set_database_path(optarg); + razor_set_database_uri(optarg); break; case opt_help: default: @@ -1949,12 +1949,12 @@ printf(" --help " "Show this help message and exit\n"); printf(" --help-commands List commands\n"); - printf(" --database=PATH " + printf(" --database=URI " "Use alternative database\n"); - printf(" --root=ROOT " - "Use ROOT as top level directory\n"); - printf(" --url=URL " - "Use URL as upstream repository\n"); + printf(" --root=URI " + "Use URI as top level directory\n"); + printf(" --url=URI " + "Use URI as upstream repository\n"); return opt != opt_help; case opt_root: install_root = optarg; diff -r 7442b30ecaae -r 008c75a5e08d test/Makefile.am --- a/test/Makefile.am Sat Jun 11 17:56:48 2016 +0100 +++ b/test/Makefile.am Mon Jul 04 10:48:18 2016 +0100 @@ -4,7 +4,7 @@ if HAVE_LUA check_SCRIPTS += lua mult-install endif -check_SCRIPTS += order +check_SCRIPTS += order non-ascii relative-root relocate: relocate.sh primary.xml.gz cp $(srcdir)/relocate.sh relocate @@ -24,6 +24,12 @@ order: order.sh primary.xml.gz cp $(srcdir)/order.sh order +non-ascii: non-ascii.sh primary.xml.gz + cp $(srcdir)/non-ascii.sh non-ascii + +relative-root: relative-root.sh primary.xml.gz + cp $(srcdir)/relative-root.sh relative-root + lua: lua.sh primary.xml.gz cp $(srcdir)/lua.sh lua @@ -40,25 +46,26 @@ rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh.spec rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/zsh2.spec rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/filesystem.spec - mkdir -p base/rpms - mv rpmbuild/RPMS/noarch/*.rpm base/rpms + rpmbuild --define "_topdir `pwd`/rpmbuild" -bb $(srcdir)/aljip.spec + mkdir -p base/Packages + mv rpmbuild/RPMS/noarch/*.rpm base/Packages rm -rf rpmbuild - createrepo --simple-md-filenames -o base base/rpms + createrepo --simple-md-filenames base updates/repodata/primary.xml.gz: zip.spec Makefile rm -rf rpmbuild updates mkdir -p rpmbuild/BUILD rpmbuild/RPMS rpmbuild --define "_topdir `pwd`/rpmbuild" --define "_version 2" \ -bb $(srcdir)/zip.spec - mkdir -p updates/rpms - mv rpmbuild/RPMS/noarch/*.rpm updates/rpms + mkdir -p updates/Packages + mv rpmbuild/RPMS/noarch/*.rpm updates/Packages rm -rf rpmbuild - createrepo --simple-md-filenames -o updates updates/rpms + createrepo --simple-md-filenames updates primary.xml.gz: base/repodata/primary.xml.gz cp base/repodata/primary.xml.gz base/repodata/filelists.xml.gz . rm -rf rpms - ln -s base/rpms . + ln -s base/Packages rpms TESTS = $(check_SCRIPTS) @@ -68,7 +75,10 @@ zsh.spec \ zsh2.spec \ filesystem.spec \ + aljip.spec \ order.sh \ + non-ascii.sh \ + relative-root.sh \ mult-install.sh \ lua.sh \ remove.sh \ diff -r 7442b30ecaae -r 008c75a5e08d test/aljip.spec --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/aljip.spec Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,35 @@ +%define _source_payload w9.gzdio +%define _binary_payload w9.gzdio + +Name: aljip +Summary: Test package +Group: Test +License: GPL +Version: %{_version} +Release: 1 +Source: aljip.tar +BuildArch: noarch +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Prefix: /usr + +%description +Test package + +%prep + +%build + +%install +mkdir -p $RPM_BUILD_ROOT/usr/bin +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/data file.alz" +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/-._~.alz" +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/!$&'()*+,;=.alz" +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/:?#[]@.alz" +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/sébastien.alz" +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/lukáš.alz" +echo %{name}-%{version}-%{release} > "$RPM_BUILD_ROOT/usr/bin/알집.sh" + +%clean + +%files +/usr/bin/* diff -r 7442b30ecaae -r 008c75a5e08d test/details.sh --- a/test/details.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/details.sh Mon Jul 04 10:48:18 2016 +0100 @@ -4,11 +4,12 @@ else razor=../src/razor fi -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install zsh2 || exit 1 $razor info zsh2 > details.out || exit 1 diff -u $srcdir/details.ref details.out || exit 1 -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/lua.sh --- a/test/lua.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/lua.sh Mon Jul 04 10:48:18 2016 +0100 @@ -6,23 +6,24 @@ fi check_filesystem() { - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir$1" ]; then echo $1: Not in filesystem >&2 exit 1 fi } check_file() { - ../src/razor list-files | grep -x "$1" > /dev/null + ../src/razor list-files | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database >&2 exit 1 fi check_filesystem "$1" } -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install filesystem || exit 1 check_file /etc @@ -30,4 +31,4 @@ check_file /usr/lib check_file /usr/include check_filesystem /media/cdrom -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/mult-install.sh --- a/test/mult-install.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/mult-install.sh Mon Jul 04 10:48:18 2016 +0100 @@ -6,37 +6,37 @@ fi fs_check_file() { - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir$1" ]; then echo $1: Not in filesystem >&2 - ls -R "$RAZOR_ROOT" >&2 + ls -R "$tmpdir" >&2 exit 1 fi } fs_check_file_contents() { fs_check_file "$1" - if [ `cat "$RAZOR_ROOT$1"` != "$2" ]; then + if [ `cat "$tmpdir$1"` != "$2" ]; then echo $1: Unexpected contents >&2 - cat "$RAZOR_ROOT$1" >&2 + cat "$tmpdir$1" >&2 exit 1 fi } fs_check_no_file() { - if [ -e "$RAZOR_ROOT$1" ]; then + if [ -e "$tmpdir$1" ]; then echo $1: Still in filesystem >&2 exit 1 fi } check_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database >&2 $razor list-files >&2 exit 1 fi - $razor list-files "$1" | grep -x "$1" > /dev/null + $razor list-files "$1" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not seen by patterned list >&2 $razor list-files "$1" >&2 @@ -50,7 +50,7 @@ fi for nevra in "$pkgs"; do name=`echo $nevra | sed 's/\-.*$//'` - $razor list-package-files "$name" | grep -x "$1" > /dev/null + $razor list-package-files "$name" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database for package $name >&2 $razor list-package-files "$name" @@ -61,7 +61,7 @@ } check_no_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -eq 0 ]; then echo $1: Still in database >&2 exit 1 @@ -76,9 +76,10 @@ exit 1 fi } -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install --relocate /usr=/opt zip || exit 1 fs_check_file_contents /opt/bin/zip zip-1-1 @@ -87,4 +88,4 @@ check_install_count zip 2 $razor install --relocate /usr=/opt zip || exit 1 check_install_count zip 3 -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/named-root.sh --- a/test/named-root.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/named-root.sh Mon Jul 04 10:48:18 2016 +0100 @@ -6,19 +6,19 @@ fi check_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database >&2 $razor list-files >&2 exit 1 fi - $razor list-files c: | grep -x "$1" > /dev/null + $razor list-files c: | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not seen by named root list >&2 $razor list-files c: >&2 exit 1 fi - $razor list-files "$1" | grep -x "$1" > /dev/null + $razor list-files "$1" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not seen by patterned list >&2 $razor list-files "$1" >&2 @@ -32,24 +32,23 @@ fi for nevra in "$pkgs"; do name=`echo $nevra | sed 's/\-.*$//'` - $razor list-package-files "$name" | grep -x "$1" > /dev/null + $razor list-package-files "$name" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database for package $name >&2 $razor list-package-files "$name" exit 1 fi done - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir/$1" ]; then echo $1: Not in filesystem >&2 exit 1 fi } tmpdir=`mktemp -dt` || exit 1 -export RAZOR_ROOT="$tmpdir/x-" -mkdir -p "$tmpdir/x-/var/lib" "$tmpdir/x-c:" +export RAZOR_ROOT="file:$tmpdir" export RAZOR_NO_ROOT_NAME_CHECKS=1 $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install --relocate /usr=c:/test zap || exit 1 $razor install --relocate /usr=c:/test zip || exit 1 diff -r 7442b30ecaae -r 008c75a5e08d test/non-ascii.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/non-ascii.sh Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,34 @@ +#!/bin/sh +if [ $# -gt 0 ]; then + razor="$1" +else + razor=../src/razor +fi +check_file() +{ + $razor list-files | grep -F -x "$1" > /dev/null + if [ $? -ne 0 ]; then + echo $1: Not in database >&2 + $razor list-files >&2 + exit 1 + fi + if [ ! -e "$tmpdir$1" ]; then + echo $1: Not in filesystem >&2 + ls -R "$tmpdir" >&2 + exit 1 + fi +} +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" +$razor init || exit 1 +export YUM_URL="file:`pwd`/base" +$razor import-yum || exit 1 +$razor install aljip || exit 1 +check_file "/usr/bin/data file.alz" +check_file "/usr/bin/-._~.alz" +check_file "/usr/bin/!$&'()*+,;=.alz" +check_file "/usr/bin/:?#[]@.alz" +check_file "/usr/bin/sébastien.alz" +check_file "/usr/bin/lukáš.alz" +check_file "/usr/bin/알집.sh" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/order.sh --- a/test/order.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/order.sh Mon Jul 04 10:48:18 2016 +0100 @@ -6,16 +6,17 @@ fi check_file() { - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir$1" ]; then echo $1: Not in filesystem >&2 exit 1 fi } -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install zip zsh || exit 1 check_file /usr/var/lib/zip/data.zap check_file /usr/var/lib/zsh/data.zip -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/relative-root.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/relative-root.sh Mon Jul 04 10:48:18 2016 +0100 @@ -0,0 +1,32 @@ +#!/bin/sh +if [ $# -gt 0 ]; then + razor="$1" +else + razor=`pwd`/../src/razor +fi +check_file() +{ + (cd /tmp; $razor list-files) | grep -F -x "$1" > /dev/null + if [ $? -ne 0 ]; then + echo $1: Not in database >&2 + (cd /tmp; $razor list-files) >&2 + exit 1 + fi + if [ ! -e "$tmpdir$1" ]; then + echo $1: Not in filesystem >&2 + ls -R "$tmpdir" >&2 + exit 1 + fi +} +tmpdir=`mktemp --directory --tmpdir=/tmp` || exit 1 +export RAZOR_ROOT="`echo $tmpdir | sed -e 's&/tmp/&file:&'`" +(cd /tmp; $razor init) || exit 1 +export YUM_URL="file:`pwd`/base" +(cd /tmp; $razor import-yum) || exit 1 +(cd /tmp; $razor install zap) || exit 1 +(cd /tmp; $razor install --relocate /usr=/opt --relocate /etc=/opt/etc zsh) || exit 1 +check_file /etc/zsh.conf +check_file /usr/bin/zap +check_file /opt/bin/zip +check_file /opt/bin/zsh +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/relocate.sh --- a/test/relocate.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/relocate.sh Mon Jul 04 10:48:18 2016 +0100 @@ -1,4 +1,5 @@ #!/bin/sh +set -x if [ $# -gt 0 ]; then razor="$1" else @@ -6,19 +7,20 @@ fi check_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database >&2 exit 1 fi - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir$1" ]; then echo $1: Not in filesystem >&2 exit 1 fi } -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install zap || exit 1 $razor install --relocate /usr=/opt --relocate /etc=/opt/etc zsh || exit 1 @@ -26,4 +28,4 @@ check_file /usr/bin/zap check_file /opt/bin/zip check_file /opt/bin/zsh -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/remove.sh --- a/test/remove.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/remove.sh Mon Jul 04 10:48:18 2016 +0100 @@ -6,28 +6,28 @@ fi fs_check_file() { - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir$1" ]; then echo $1: Not in filesystem >&2 - ls -R "$RAZOR_ROOT" >&2 + ls -R "$tmpdir" >&2 exit 1 fi } fs_check_no_file() { - if [ -e "$RAZOR_ROOT$1" ]; then + if [ -e "$tmpdir$1" ]; then echo $1: Still in filesystem >&2 exit 1 fi } check_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database >&2 $razor list-files >&2 exit 1 fi - $razor list-files "$1" | grep -x "$1" > /dev/null + $razor list-files "$1" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not seen by patterned list >&2 $razor list-files "$1" >&2 @@ -41,7 +41,7 @@ fi for nevra in "$pkgs"; do name=`echo $nevra | sed 's/\-.*$//'` - $razor list-package-files "$name" | grep -x "$1" > /dev/null + $razor list-package-files "$name" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database for package $name >&2 $razor list-package-files "$name" @@ -52,16 +52,17 @@ } check_no_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -eq 0 ]; then echo $1: Still in database >&2 exit 1 fi fs_check_no_file $1 } -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" +export YUM_URL="file:`pwd`/base" $razor import-yum || exit 1 $razor install --relocate /usr=/opt zip || exit 1 fs_check_file /opt/var/lib/zip/data.zap @@ -81,4 +82,4 @@ fs_check_file /opt/var/lib/zip/data.zap $razor remove zsh2 zip || exit 1 fs_check_no_file /opt/var/lib/zip/data.zap -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir" diff -r 7442b30ecaae -r 008c75a5e08d test/update.sh --- a/test/update.sh Sat Jun 11 17:56:48 2016 +0100 +++ b/test/update.sh Mon Jul 04 10:48:18 2016 +0100 @@ -6,37 +6,37 @@ fi fs_check_file() { - if [ ! -e "$RAZOR_ROOT$1" ]; then + if [ ! -e "$tmpdir$1" ]; then echo $1: Not in filesystem >&2 - ls -R "$RAZOR_ROOT" >&2 + ls -R "$tmpdir" >&2 exit 1 fi } fs_check_file_contents() { fs_check_file "$1" - if [ `cat "$RAZOR_ROOT$1"` != "$2" ]; then + if [ `cat "$tmpdir$1"` != "$2" ]; then echo $1: Unexpected contents >&2 - cat "$RAZOR_ROOT$1" >&2 + cat "$tmpdir$1" >&2 exit 1 fi } fs_check_no_file() { - if [ -e "$RAZOR_ROOT$1" ]; then + if [ -e "$tmpdir$1" ]; then echo $1: Still in filesystem >&2 exit 1 fi } check_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database >&2 $razor list-files >&2 exit 1 fi - $razor list-files "$1" | grep -x "$1" > /dev/null + $razor list-files "$1" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not seen by patterned list >&2 $razor list-files "$1" >&2 @@ -50,7 +50,7 @@ fi for nevra in "$pkgs"; do name=`echo $nevra | sed 's/\-.*$//'` - $razor list-package-files "$name" | grep -x "$1" > /dev/null + $razor list-package-files "$name" | grep -F -x "$1" > /dev/null if [ $? -ne 0 ]; then echo $1: Not in database for package $name >&2 $razor list-package-files "$name" @@ -61,7 +61,7 @@ } check_no_file() { - $razor list-files | grep -x "$1" > /dev/null + $razor list-files | grep -F -x "$1" > /dev/null if [ $? -eq 0 ]; then echo $1: Still in database >&2 exit 1 @@ -78,13 +78,14 @@ } set_repository() { + export YUM_URL="file:`pwd`/$1" cp $1/repodata/primary.xml.gz $1/repodata/filelists.xml.gz . rm -rf rpms - ln -s $1/rpms . + ln -s $1/Packages rpms } -export RAZOR_ROOT=`mktemp -dt` || exit 1 +tmpdir=`mktemp -dt` || exit 1 +export RAZOR_ROOT="file:$tmpdir" $razor init || exit 1 -export YUM_URL="file://localhost/`pwd`" set_repository base $razor import-yum || exit 1 $razor install --relocate /usr=/opt zip || exit 1 @@ -118,4 +119,4 @@ $razor install --relocate /usr=/opt zip || exit 1 $razor update --relocate /usr=/opt zip || exit 1 check_install_count zip 1 -rm -rf "$RAZOR_ROOT" +rm -rf "$tmpdir"