librazor/util.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 339 159067260aad
child 372 6e93e5485947
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #include "config.h"
    22 
    23 #include <limits.h>
    24 #include <string.h>
    25 #include <sys/types.h>
    26 #include <sys/stat.h>
    27 #include <stdlib.h>
    28 #include <stdio.h>
    29 #include <stdint.h>
    30 #include <errno.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 #ifdef MSWIN_API
    34 #include <direct.h>
    35 #endif
    36 #if HAVE_SYS_MMAN_H
    37 #include <sys/mman.h>
    38 #endif
    39 
    40 #include "razor.h"
    41 #include "razor-internal.h"
    42 
    43 #ifndef O_BINARY
    44 #define O_BINARY	0
    45 #endif
    46 
    47 #define RAZOR_ASCII_ISALPHA(c)	\
    48 			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
    49 
    50 /* Required by gnulib on non-libc platforms */
    51 char *program_name = "librazor";
    52 
    53 static int allow_all_root_names = 0;
    54 
    55 /*
    56  * Primarily intended for testing named roots under UNIX platforms.
    57  */
    58 RAZOR_EXPORT void razor_disable_root_name_checks(int disable)
    59 {
    60 	allow_all_root_names = disable;
    61 }
    62 
    63 static int razor_valid_root_name(const char *name)
    64 {
    65 	if (allow_all_root_names)
    66 		return !strchr(name,'/');
    67 
    68 #ifdef MSWIN_API
    69 	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
    70 	       name[2] == '\0';
    71 #else
    72 	return name[0] == '\0';
    73 #endif
    74 }
    75 
    76 int
    77 razor_create_dir(const char *root, const char *path)
    78 {
    79 	char buffer[PATH_MAX], *p;
    80 	const char *slash, *next;
    81 	struct stat buf;
    82 
    83 	/* Create all sub-directories in dir. We know root exists and
    84 	 * is a dir, root does not end in a '/', and path either has a
    85 	 * leading '/' or (on MS-Windows only) root is the empty string
    86 	 * and path starts with drive (eg., "c:/windows"). */
    87 
    88 	strcpy(buffer, root);
    89 	p = buffer + strlen(buffer);
    90 	slash = path;
    91 	for (slash = path; *slash != '\0'; slash = next) {
    92 		next = strchr(slash + 1, '/');
    93 		if (next == NULL)
    94 			break;
    95 
    96 		memcpy(p, slash, next - slash);
    97 		p += next - slash;
    98 		*p = '\0';
    99 
   100 		if (razor_valid_root_name(buffer))
   101 			continue;
   102 
   103 		if (stat(buffer, &buf) == 0) {
   104 			if (!S_ISDIR(buf.st_mode)) {
   105 				fprintf(stderr,
   106 					"%s exists but is not a directory\n",
   107 					buffer);
   108 				return -1;
   109 			}
   110 		} else if (mkdir(buffer, 0777) < 0) {
   111 			fprintf(stderr, "failed to make directory %s: %s\n",
   112 				buffer, strerror(errno));
   113 			return -1;
   114 		}
   115 
   116 		/* FIXME: What to do about permissions for dirs we
   117 		 * have to create but are not in the cpio archive? */
   118 	}
   119 
   120 	return 0;
   121 }
   122 
   123 int
   124 razor_write(int fd, const void *data, size_t size)
   125 {
   126 	size_t rest;
   127 	ssize_t written;
   128 	const unsigned char *p;
   129 
   130 	rest = size;
   131 	p = data;
   132 	while (rest > 0) {
   133 		written = write(fd, p, rest);
   134 		if (written < 0) {
   135 			perror("write error");
   136 			return -1;
   137 		}
   138 		rest -= written;
   139 		p += written;
   140 	}
   141 
   142 	return 0;
   143 }
   144 
   145 void *
   146 razor_file_get_contents(const char *filename, size_t *length)
   147 {
   148 	int fd;
   149 	struct stat st;
   150 	void *addr;
   151 #if !HAVE_SYS_MMAN_H
   152 	size_t nb;
   153 	ssize_t res;
   154 #endif
   155 
   156 	fd = open(filename, O_RDONLY | O_BINARY);
   157 	if (fd < 0)
   158 		return NULL;
   159 
   160 	if (fstat(fd, &st) < 0) {
   161 		close(fd);
   162 		return NULL;
   163 	}
   164 
   165 	*length = st.st_size;
   166 #if HAVE_SYS_MMAN_H
   167 	addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   168 #else
   169 	addr = malloc(st.st_size);
   170 	if (addr) {
   171 		nb = 0;
   172 		while(nb < st.st_size) {
   173 			res = read(fd, addr + nb, st.st_size - nb);
   174 			if (res <= 0) {
   175 				free(addr);
   176 				addr = NULL;
   177 				break;
   178 			}
   179 			nb += res;
   180 		}
   181 	}
   182 #endif
   183 	close(fd);
   184 
   185 #if HAVE_SYS_MMAN_H
   186 	if (addr == MAP_FAILED)
   187 		addr = NULL;
   188 #endif
   189 
   190 	return addr;
   191 }
   192 
   193 int
   194 razor_file_free_contents(void *addr, size_t length)
   195 {
   196 #if HAVE_SYS_MMAN_H
   197 	return munmap(addr, length);
   198 #else
   199 	free(addr);
   200 	return 0;
   201 #endif
   202 }
   203 
   204 struct qsort_context {
   205 	size_t size;
   206 	razor_compare_with_data_func_t compare;
   207 	void *data;
   208 };
   209 
   210 static void
   211 qsort_swap(void *p1, void *p2, size_t size)
   212 {
   213 	char buffer[size];
   214 
   215 	memcpy(buffer, p1, size);
   216 	memcpy(p1, p2, size);
   217 	memcpy(p2, buffer, size);
   218 }
   219 
   220 static void
   221 __qsort_with_data(void *base, size_t nelem, uint32_t *map,
   222 		  struct qsort_context *ctx)
   223 {
   224 	void *p, *start, *end, *pivot;
   225 	uint32_t *mp, *mstart, *mend, tmp;
   226 	int left, right, result;
   227 	size_t size = ctx->size;
   228 
   229 	p = base;
   230 	start = base;
   231 	end = base + nelem * size;
   232 	mp = map;
   233 	mstart = map;
   234 	mend = map + nelem;
   235 	pivot = base + (rand() % nelem) * size;
   236 
   237 	while (p < end) {
   238 		result = ctx->compare(p, pivot, ctx->data);
   239 		if (result < 0) {
   240 			qsort_swap(p, start, size);
   241 			tmp = *mp;
   242 			*mp = *mstart;
   243 			*mstart = tmp;
   244 			if (start == pivot)
   245 				pivot = p;
   246 			start += size;
   247 			mstart++;
   248 			p += size;
   249 			mp++;
   250 		} else if (result == 0) {
   251 			p += size;
   252 			mp++;
   253 		} else {
   254  			end -= size;
   255 			mend--;
   256 			qsort_swap(p, end, size);
   257 			tmp = *mp;
   258 			*mp = *mend;
   259 			*mend = tmp;
   260 			if (end == pivot)
   261 				pivot = p;
   262 		}
   263 	}
   264 
   265 	left = (start - base) / size;
   266 	right = (base + nelem * size - end) / size;
   267 	if (left > 1)
   268 		__qsort_with_data(base, left, map, ctx);
   269 	if (right > 1)
   270 		__qsort_with_data(end, right, mend, ctx);
   271 }
   272 
   273 uint32_t *
   274 razor_qsort_with_data(void *base, size_t nelem, size_t size,
   275 		      razor_compare_with_data_func_t compare, void *data)
   276 {
   277 	struct qsort_context ctx;
   278 	uint32_t *map;
   279 	int i;
   280 
   281 	if (nelem == 0)
   282 		return NULL;
   283 
   284 	ctx.size = size;
   285 	ctx.compare = compare;
   286 	ctx.data = data;
   287 
   288 	map = malloc(nelem * sizeof (uint32_t));
   289 	for (i = 0; i < nelem; i++)
   290 		map[i] = i;
   291 
   292 	__qsort_with_data(base, nelem, map, &ctx);
   293 
   294 	return map;
   295 }