librazor/util.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Oct 22 12:09:47 2014 +0100 (2014-10-22)
changeset 460 b8638c3c7eee
parent 455 df914f383f5c
child 475 008c75a5e08d
permissions -rw-r--r--
Add basic checks for rpm file format
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012, 2014  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 <windows.h>
    35 #include <direct.h>
    36 #else
    37 #include <sys/utsname.h>
    38 #endif
    39 #if HAVE_SYS_MMAN_H
    40 #include <sys/mman.h>
    41 #endif
    42 #include <assert.h>
    43 
    44 #include "razor.h"
    45 #include "razor-internal.h"
    46 
    47 #ifndef O_BINARY
    48 #define O_BINARY	0
    49 #endif
    50 
    51 /* Required by gnulib on non-libc platforms */
    52 char *program_name = "librazor";
    53 
    54 void *
    55 zalloc(size_t size)
    56 {
    57 	void *p;
    58 
    59 	p = malloc(size);
    60 	memset(p, 0, size);
    61 
    62 	return p;
    63 }
    64 
    65 #if HAVE_SYS_MMAN_H
    66 #define OPEN_FILE_USED		(1U<<0)
    67 #define OPEN_FILE_MMAPPED	(1U<<1)
    68 
    69 struct open_file {
    70 	void *addr;
    71 	size_t length;
    72 	uint32_t flags;
    73 };
    74 
    75 struct array open_files = { 0, };
    76 #endif	/* HAVE_SYS_MMAN_H */
    77 
    78 void *
    79 razor_file_get_contents(const char *filename, size_t *length, int private,
    80 			struct razor_error **error)
    81 {
    82 	int fd;
    83 	struct stat st;
    84 	void *addr = NULL;
    85 	size_t nb;
    86 	ssize_t res;
    87 #if HAVE_SYS_MMAN_H
    88 	struct open_file *of, *ofend;
    89 #endif
    90 
    91 	fd = open(filename, O_RDONLY | O_BINARY);
    92 	if (fd < 0) {
    93 		razor_set_error_posix(error, filename);
    94 		return NULL;
    95 	}
    96 
    97 	if (fstat(fd, &st) < 0) {
    98 		razor_set_error_posix(error, filename);
    99 		close(fd);
   100 		return NULL;
   101 	}
   102 
   103 	*length = st.st_size;
   104 
   105 #if HAVE_SYS_MMAN_H
   106 	ofend = open_files.data + open_files.size;
   107 	for (of = open_files.data; of < ofend; of++)
   108 		if (!(of->flags & OPEN_FILE_USED))
   109 			break;
   110 	if (of == ofend) {
   111 		of = array_add(&open_files, sizeof *of);
   112 		of->flags = 0;
   113 	}
   114 
   115 	if (!private) {
   116 		addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   117 		if (addr == MAP_FAILED)
   118 			addr = NULL;
   119 		else
   120 			of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED;
   121 	}
   122 #endif	/* HAVE_SYS_MMAN_H */
   123 	if (!addr) {
   124 		addr = malloc(st.st_size);
   125 		if (addr) {
   126 #if HAVE_SYS_MMAN_H
   127 			of->flags = OPEN_FILE_USED;
   128 #endif
   129 			nb = 0;
   130 			while(nb < st.st_size) {
   131 				res = read(fd, addr + nb, st.st_size - nb);
   132 				if (res <= 0) {
   133 					razor_set_error_posix(error, filename);
   134 					free(addr);
   135 					addr = NULL;
   136 					break;
   137 				}
   138 				nb += res;
   139 			}
   140 		} else
   141 			razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   142 					"Not enough memory");
   143 	}
   144 	close(fd);
   145 
   146 #if HAVE_SYS_MMAN_H
   147 	of->addr = addr;
   148 	of->length = st.st_size;
   149 #endif
   150 
   151 	return addr;
   152 }
   153 
   154 int razor_file_free_contents(void *addr, size_t length)
   155 {
   156 #if HAVE_SYS_MMAN_H
   157 	int retval, mmapped;
   158 	struct open_file *of, *ofend;
   159 
   160 	ofend = open_files.data + open_files.size;
   161 	for (of = open_files.data; of < ofend; of++)
   162 		if ((of->flags & OPEN_FILE_USED) && of->addr == addr)
   163 			break;
   164 
   165 	if (of == ofend)
   166 		return 1;
   167 
   168 	length = of->length;
   169 	mmapped = of->flags & OPEN_FILE_MMAPPED;
   170 	of->flags &= ~OPEN_FILE_USED;
   171 
   172 	for (of = open_files.data; of < ofend; of++)
   173 		if (of->flags & OPEN_FILE_USED)
   174 			break;
   175 
   176 	if (of == ofend) {
   177 		array_release(&open_files);
   178 		array_init(&open_files);
   179 	}
   180 
   181 	if (mmapped)
   182 		return munmap(addr, length);
   183 #endif
   184 
   185 	free(addr);
   186 	return 0;
   187 }
   188 
   189 struct qsort_context {
   190 	size_t size;
   191 	razor_compare_with_data_func_t compare;
   192 	void *data;
   193 };
   194 
   195 static void
   196 qsort_swap(void *p1, void *p2, size_t size)
   197 {
   198 	char buffer[size];
   199 
   200 	if (p1 != p2) {
   201 		memcpy(buffer, p1, size);
   202 		memcpy(p1, p2, size);
   203 		memcpy(p2, buffer, size);
   204 	}
   205 }
   206 
   207 static void
   208 __qsort_with_data(void *base, size_t nelem, uint32_t *map,
   209 		  struct qsort_context *ctx)
   210 {
   211 	void *p, *start, *end, *pivot;
   212 	uint32_t *mp, *mstart, *mend, tmp;
   213 	int left, right, result;
   214 	size_t size = ctx->size;
   215 
   216 	p = base;
   217 	start = base;
   218 	end = base + nelem * size;
   219 	mp = map;
   220 	mstart = map;
   221 	mend = map + nelem;
   222 	pivot = base + (rand() % nelem) * size;
   223 
   224 	while (p < end) {
   225 		result = ctx->compare(p, pivot, ctx->data);
   226 		if (result < 0) {
   227 			qsort_swap(p, start, size);
   228 			tmp = *mp;
   229 			*mp = *mstart;
   230 			*mstart = tmp;
   231 			if (start == pivot)
   232 				pivot = p;
   233 			start += size;
   234 			mstart++;
   235 			p += size;
   236 			mp++;
   237 		} else if (result == 0) {
   238 			p += size;
   239 			mp++;
   240 		} else {
   241  			end -= size;
   242 			mend--;
   243 			qsort_swap(p, end, size);
   244 			tmp = *mp;
   245 			*mp = *mend;
   246 			*mend = tmp;
   247 			if (end == pivot)
   248 				pivot = p;
   249 		}
   250 	}
   251 
   252 	left = (start - base) / size;
   253 	right = (base + nelem * size - end) / size;
   254 	if (left > 1)
   255 		__qsort_with_data(base, left, map, ctx);
   256 	if (right > 1)
   257 		__qsort_with_data(end, right, mend, ctx);
   258 }
   259 
   260 uint32_t *
   261 razor_qsort_with_data(void *base, size_t nelem, size_t size,
   262 		      razor_compare_with_data_func_t compare, void *data)
   263 {
   264 	struct qsort_context ctx;
   265 	uint32_t *map;
   266 	int i;
   267 
   268 	if (nelem == 0)
   269 		return NULL;
   270 
   271 	ctx.size = size;
   272 	ctx.compare = compare;
   273 	ctx.data = data;
   274 
   275 	map = malloc(nelem * sizeof (uint32_t));
   276 	for (i = 0; i < nelem; i++)
   277 		map[i] = i;
   278 
   279 	__qsort_with_data(base, nelem, map, &ctx);
   280 
   281 	return map;
   282 }
   283 
   284 void environment_init(struct environment *env)
   285 {
   286 	env->is_set = 0;
   287 	array_init(&env->string_pool);
   288 	array_init(&env->vars);
   289 }
   290 
   291 void environment_add_variable(struct environment *env,
   292 			      const char *variable, const char *value)
   293 {
   294 	char *s;
   295 	uint32_t *r;
   296 	assert(!env->is_set);
   297 
   298 	s = array_add(&env->string_pool,
   299 		      strlen(variable) + strlen(value) + 2);
   300 	sprintf(s, "%s=%s", variable, value);
   301 	r = array_add(&env->vars, sizeof *r);
   302 	*r = s - (char *)env->string_pool.data;
   303 }
   304 
   305 void environment_set(struct environment *env)
   306 {
   307 	int i, count;
   308 	char *s;
   309 #ifndef WIN32
   310 	char *t;
   311 #endif
   312         uint32_t *r;
   313 
   314 	if (!env->is_set) {
   315 		count = env->vars.size / sizeof(uint32_t);
   316 		r = (uint32_t *)env->vars.data;
   317 		for (i = 0; i < count; i++) {
   318 			s = env->string_pool.data + *r++;
   319 #ifdef WIN32
   320 			putenv(s);
   321 #else
   322 			t = strchr(s, '=');
   323 			*t = '\0';
   324 			setenv(s, t + 1, 1);
   325 			*t = '=';
   326 #endif
   327 		}
   328 
   329 		env->is_set = 1;
   330 	}
   331 }
   332 
   333 void environment_unset(struct environment *env)
   334 {
   335 	int i, count;
   336 	char c, *s, *t;
   337         uint32_t *r;
   338 
   339 	if (env->is_set) {
   340 		count = env->vars.size / sizeof(uint32_t);
   341 		r = (uint32_t *)env->vars.data;
   342 		for (i = 0; i < count; i++) {
   343 			s = env->string_pool.data + *r++;
   344 			t = strchr(s, '=');
   345 #ifdef WIN32
   346 			t++;
   347 			c = *t;
   348 			*t = '\0';
   349 			putenv(s);
   350 			*t = c;
   351 #else
   352 			c = *t;
   353 			*t = '\0';
   354 			unsetenv(s);
   355 			*t = c;
   356 #endif
   357 		}
   358 
   359 		env->is_set = 0;
   360 	}
   361 }
   362 
   363 void environment_release(struct environment *env)
   364 {
   365 	environment_unset(env);
   366 	array_release(&env->string_pool);
   367 	array_release(&env->vars);
   368 }
   369 
   370 RAZOR_EXPORT char *razor_concat(const char *s, ...)
   371 {
   372 	va_list args;
   373 	const char *string;
   374 	char *concat;
   375 	size_t n, len;
   376 
   377 	va_start(args, s);
   378 
   379 	len = strlen(s);
   380 	while((string = va_arg(args, const char *)))
   381 		len += strlen(string);
   382 
   383 	va_end(args);
   384 
   385 	concat = malloc(len + 1);
   386 
   387 	if (!concat)
   388 		return NULL;
   389 
   390 	va_start(args, s);
   391 
   392 	len = strlen(s);
   393 	memcpy(concat, s, len);
   394 	n = len;
   395 	while((string = va_arg(args, const char *))) {
   396 		len = strlen(string);
   397 		memcpy(concat + n, string, len);
   398 		n += len;
   399 	}
   400 
   401 	va_end(args);
   402 
   403 	concat[n] = '\0';
   404 
   405 	return concat;
   406 }
   407 
   408 RAZOR_EXPORT const char *razor_system_arch(void)
   409 {
   410 #ifdef MSWIN_API
   411 	SYSTEM_INFO si;
   412 
   413 	GetNativeSystemInfo(&si);
   414 	switch(si.wProcessorArchitecture)
   415 	{
   416 		case PROCESSOR_ARCHITECTURE_INTEL:
   417 			return "i686";
   418 		case PROCESSOR_ARCHITECTURE_AMD64:
   419 			return "x86_64";
   420 		default:
   421 			return NULL;
   422 	}
   423 #else
   424 	static struct utsname un;
   425 
   426 	if (uname(&un))
   427 		return NULL;
   428 	else
   429 		return un.machine;
   430 #endif
   431 }
   432 
   433 #ifdef MSWIN_API
   434 
   435 char *razor_utf16_to_utf8(const wchar_t *utf16, int len)
   436 {
   437 	int n;
   438 	char *utf8;
   439 
   440 	if (len == 0)
   441 		return strdup("");
   442 
   443 	n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
   444 	if (len > 0)
   445 		n++;
   446 	utf8 = malloc(n);
   447 	(void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL);
   448 	if (len > 0)
   449 		utf8[n - 1] = 0;
   450 
   451 	return utf8;
   452 }
   453 
   454 wchar_t *razor_utf8_to_utf16(const char *utf8, int len)
   455 {
   456 	int n;
   457 	wchar_t *utf16;
   458 
   459 	if (len == 0) {
   460 		utf16 = calloc(1, sizeof(wchar_t));
   461 		return utf16;
   462 	}
   463 
   464 	n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
   465 	if (len > 0)
   466 		n++;
   467 	utf16 = malloc(n * sizeof(wchar_t));
   468 	(void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n);
   469 	if (len > 0)
   470 		utf16[n - 1] = 0;
   471 
   472 	return utf16;
   473 }
   474 
   475 #endif	/* MSWIN_API */