librazor/util.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Jul 03 18:02:33 2009 +0100 (2009-07-03)
changeset 372 6e93e5485947
parent 359 c9c90315ea24
child 377 5549419824b4
permissions -rw-r--r--
Support RPM_INSTALL_PREFIX{n} during uninstall
     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 #include <assert.h>
    40 
    41 #include "razor.h"
    42 #include "razor-internal.h"
    43 
    44 #ifndef O_BINARY
    45 #define O_BINARY	0
    46 #endif
    47 
    48 #define RAZOR_ASCII_ISALPHA(c)	\
    49 			((c) >= 'A' && (c) <= 'Z' || (c) >= 'a' && (c) <= 'z')
    50 
    51 /* Required by gnulib on non-libc platforms */
    52 char *program_name = "librazor";
    53 
    54 static int allow_all_root_names = 0;
    55 
    56 /*
    57  * Primarily intended for testing named roots under UNIX platforms.
    58  */
    59 RAZOR_EXPORT void razor_disable_root_name_checks(int disable)
    60 {
    61 	allow_all_root_names = disable;
    62 }
    63 
    64 static int razor_valid_root_name(const char *name)
    65 {
    66 	if (allow_all_root_names)
    67 		return !strchr(name,'/');
    68 
    69 #ifdef MSWIN_API
    70 	return RAZOR_ASCII_ISALPHA(name[0]) && name[1] == ':' &&
    71 	       name[2] == '\0';
    72 #else
    73 	return name[0] == '\0';
    74 #endif
    75 }
    76 
    77 int
    78 razor_create_dir(const char *root, const char *path)
    79 {
    80 	char buffer[PATH_MAX], *p;
    81 	const char *slash, *next;
    82 	struct stat buf;
    83 
    84 	/* Create all sub-directories in dir. We know root exists and
    85 	 * is a dir, root does not end in a '/', and path either has a
    86 	 * leading '/' or (on MS-Windows only) root is the empty string
    87 	 * and path starts with drive (eg., "c:/windows"). */
    88 
    89 	strcpy(buffer, root);
    90 	p = buffer + strlen(buffer);
    91 	slash = path;
    92 	for (slash = path; *slash != '\0'; slash = next) {
    93 		next = strchr(slash + 1, '/');
    94 		if (next == NULL)
    95 			break;
    96 
    97 		memcpy(p, slash, next - slash);
    98 		p += next - slash;
    99 		*p = '\0';
   100 
   101 		if (razor_valid_root_name(buffer))
   102 			continue;
   103 
   104 		if (stat(buffer, &buf) == 0) {
   105 			if (!S_ISDIR(buf.st_mode)) {
   106 				fprintf(stderr,
   107 					"%s exists but is not a directory\n",
   108 					buffer);
   109 				return -1;
   110 			}
   111 		} else if (mkdir(buffer, 0777) < 0) {
   112 			fprintf(stderr, "failed to make directory %s: %s\n",
   113 				buffer, strerror(errno));
   114 			return -1;
   115 		}
   116 
   117 		/* FIXME: What to do about permissions for dirs we
   118 		 * have to create but are not in the cpio archive? */
   119 	}
   120 
   121 	return 0;
   122 }
   123 
   124 int
   125 razor_write(int fd, const void *data, size_t size)
   126 {
   127 	size_t rest;
   128 	ssize_t written;
   129 	const unsigned char *p;
   130 
   131 	rest = size;
   132 	p = data;
   133 	while (rest > 0) {
   134 		written = write(fd, p, rest);
   135 		if (written < 0) {
   136 			perror("write error");
   137 			return -1;
   138 		}
   139 		rest -= written;
   140 		p += written;
   141 	}
   142 
   143 	return 0;
   144 }
   145 
   146 void *
   147 razor_file_get_contents(const char *filename, size_t *length)
   148 {
   149 	int fd;
   150 	struct stat st;
   151 	void *addr;
   152 #if !HAVE_SYS_MMAN_H
   153 	size_t nb;
   154 	ssize_t res;
   155 #endif
   156 
   157 	fd = open(filename, O_RDONLY | O_BINARY);
   158 	if (fd < 0)
   159 		return NULL;
   160 
   161 	if (fstat(fd, &st) < 0) {
   162 		close(fd);
   163 		return NULL;
   164 	}
   165 
   166 	*length = st.st_size;
   167 #if HAVE_SYS_MMAN_H
   168 	addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   169 #else
   170 	addr = malloc(st.st_size);
   171 	if (addr) {
   172 		nb = 0;
   173 		while(nb < st.st_size) {
   174 			res = read(fd, addr + nb, st.st_size - nb);
   175 			if (res <= 0) {
   176 				free(addr);
   177 				addr = NULL;
   178 				break;
   179 			}
   180 			nb += res;
   181 		}
   182 	}
   183 #endif
   184 	close(fd);
   185 
   186 #if HAVE_SYS_MMAN_H
   187 	if (addr == MAP_FAILED)
   188 		addr = NULL;
   189 #endif
   190 
   191 	return addr;
   192 }
   193 
   194 int
   195 razor_file_free_contents(void *addr, size_t length)
   196 {
   197 #if HAVE_SYS_MMAN_H
   198 	return munmap(addr, length);
   199 #else
   200 	free(addr);
   201 	return 0;
   202 #endif
   203 }
   204 
   205 struct qsort_context {
   206 	size_t size;
   207 	razor_compare_with_data_func_t compare;
   208 	void *data;
   209 };
   210 
   211 static void
   212 qsort_swap(void *p1, void *p2, size_t size)
   213 {
   214 	char buffer[size];
   215 
   216 	memcpy(buffer, p1, size);
   217 	memcpy(p1, p2, size);
   218 	memcpy(p2, buffer, size);
   219 }
   220 
   221 static void
   222 __qsort_with_data(void *base, size_t nelem, uint32_t *map,
   223 		  struct qsort_context *ctx)
   224 {
   225 	void *p, *start, *end, *pivot;
   226 	uint32_t *mp, *mstart, *mend, tmp;
   227 	int left, right, result;
   228 	size_t size = ctx->size;
   229 
   230 	p = base;
   231 	start = base;
   232 	end = base + nelem * size;
   233 	mp = map;
   234 	mstart = map;
   235 	mend = map + nelem;
   236 	pivot = base + (rand() % nelem) * size;
   237 
   238 	while (p < end) {
   239 		result = ctx->compare(p, pivot, ctx->data);
   240 		if (result < 0) {
   241 			qsort_swap(p, start, size);
   242 			tmp = *mp;
   243 			*mp = *mstart;
   244 			*mstart = tmp;
   245 			if (start == pivot)
   246 				pivot = p;
   247 			start += size;
   248 			mstart++;
   249 			p += size;
   250 			mp++;
   251 		} else if (result == 0) {
   252 			p += size;
   253 			mp++;
   254 		} else {
   255  			end -= size;
   256 			mend--;
   257 			qsort_swap(p, end, size);
   258 			tmp = *mp;
   259 			*mp = *mend;
   260 			*mend = tmp;
   261 			if (end == pivot)
   262 				pivot = p;
   263 		}
   264 	}
   265 
   266 	left = (start - base) / size;
   267 	right = (base + nelem * size - end) / size;
   268 	if (left > 1)
   269 		__qsort_with_data(base, left, map, ctx);
   270 	if (right > 1)
   271 		__qsort_with_data(end, right, mend, ctx);
   272 }
   273 
   274 uint32_t *
   275 razor_qsort_with_data(void *base, size_t nelem, size_t size,
   276 		      razor_compare_with_data_func_t compare, void *data)
   277 {
   278 	struct qsort_context ctx;
   279 	uint32_t *map;
   280 	int i;
   281 
   282 	if (nelem == 0)
   283 		return NULL;
   284 
   285 	ctx.size = size;
   286 	ctx.compare = compare;
   287 	ctx.data = data;
   288 
   289 	map = malloc(nelem * sizeof (uint32_t));
   290 	for (i = 0; i < nelem; i++)
   291 		map[i] = i;
   292 
   293 	__qsort_with_data(base, nelem, map, &ctx);
   294 
   295 	return map;
   296 }
   297 
   298 void environment_init(struct environment *env)
   299 {
   300 	env->is_set = 0;
   301 	array_init(&env->string_pool);
   302 	array_init(&env->vars);
   303 }
   304 
   305 void environment_add_variable(struct environment *env,
   306 			      const char *variable, const char *value)
   307 {
   308 	char *s;
   309 	uint32_t *r;
   310 	assert(!env->is_set);
   311 
   312 	s = array_add(&env->string_pool,
   313 		      strlen(variable) + strlen(value) + 2);
   314 	sprintf(s, "%s=%s", variable, value);
   315 	r = array_add(&env->vars, sizeof *r);
   316 	*r = s - (char *)env->string_pool.data;
   317 }
   318 
   319 void environment_set(struct environment *env)
   320 {
   321 	int i, count;
   322 	char *s;
   323         uint32_t *r;
   324 
   325 	if (!env->is_set) {
   326 		count = env->vars.size / sizeof(uint32_t);
   327 		r = (uint32_t *)env->vars.data;
   328 		for (i = 0; i < count; i++) {
   329 			s = env->string_pool.data + *r++;
   330 			putenv(s);
   331 		}
   332 
   333 		env->is_set = 1;
   334 	}
   335 }
   336 
   337 void environment_unset(struct environment *env)
   338 {
   339 	int i, count;
   340 	char c, *s, *t;
   341         uint32_t *r;
   342 
   343 	if (env->is_set) {
   344 		count = env->vars.size / sizeof(uint32_t);
   345 		r = (uint32_t *)env->vars.data;
   346 		for (i = 0; i < count; i++) {
   347 			s = env->string_pool.data + *r++;
   348 			t = strchr(s, '=') + 1;
   349 			c = *t;
   350 			*t = '\0';
   351 			putenv(s);
   352 			*t = c;
   353 		}
   354 
   355 		env->is_set = 0;
   356 	}
   357 }
   358 
   359 void environment_release(struct environment *env)
   360 {
   361 	environment_unset(env);
   362 	array_release(&env->string_pool);
   363 	array_release(&env->vars);
   364 }