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