librazor/util.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Jun 03 08:26:09 2009 +0100 (2009-06-03)
changeset 368 ea743486ba6f
parent 339 159067260aad
child 372 6e93e5485947
permissions -rw-r--r--
Add automatic provides for lua pre-loaded modules
     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 }