richard@300: /* richard@300: * Copyright (C) 2008 Kristian Høgsberg richard@300: * Copyright (C) 2008 Red Hat, Inc ali@441: * Copyright (C) 2009, 2011, 2012, 2014 J. Ali Harlow richard@300: * richard@300: * This program is free software; you can redistribute it and/or modify richard@300: * it under the terms of the GNU General Public License as published by richard@300: * the Free Software Foundation; either version 2 of the License, or richard@300: * (at your option) any later version. richard@300: * richard@300: * This program is distributed in the hope that it will be useful, richard@300: * but WITHOUT ANY WARRANTY; without even the implied warranty of richard@300: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the richard@300: * GNU General Public License for more details. richard@300: * richard@300: * You should have received a copy of the GNU General Public License along richard@300: * with this program; if not, write to the Free Software Foundation, Inc., richard@300: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. richard@300: */ richard@300: ali@322: #include "config.h" ali@322: rhughes@241: #include rhughes@241: #include ali@322: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include ali@339: #include rhughes@241: #include ali@322: #include ali@359: #ifdef MSWIN_API ali@377: #include ali@359: #include ali@403: #else ali@403: #include ali@359: #endif ali@322: #if HAVE_SYS_MMAN_H ali@322: #include ali@322: #endif ali@372: #include rhughes@241: ali@359: #include "razor.h" rhughes@241: #include "razor-internal.h" rhughes@241: ali@322: #ifndef O_BINARY ali@322: #define O_BINARY 0 ali@322: #endif ali@322: ali@338: /* Required by gnulib on non-libc platforms */ ali@338: char *program_name = "librazor"; ali@338: ali@322: void * ali@424: zalloc(size_t size) ali@424: { ali@424: void *p; ali@424: ali@424: p = malloc(size); ali@424: memset(p, 0, size); ali@424: ali@424: return p; ali@424: } ali@424: ali@458: #if HAVE_SYS_MMAN_H ali@458: #define OPEN_FILE_USED (1U<<0) ali@458: #define OPEN_FILE_MMAPPED (1U<<1) ali@458: ali@458: struct open_file { ali@458: void *addr; ali@458: size_t length; ali@458: uint32_t flags; ali@458: }; ali@458: ali@458: struct array open_files = { 0, }; ali@458: #endif /* HAVE_SYS_MMAN_H */ ali@458: ali@424: void * ali@424: razor_file_get_contents(const char *filename, size_t *length, int private, ali@424: struct razor_error **error) ali@322: { ali@322: int fd; ali@322: struct stat st; ali@424: void *addr = NULL; ali@322: size_t nb; ali@322: ssize_t res; ali@458: #if HAVE_SYS_MMAN_H ali@458: struct open_file *of, *ofend; ali@458: #endif ali@322: ali@322: fd = open(filename, O_RDONLY | O_BINARY); ali@424: if (fd < 0) { ali@447: razor_set_error_posix(error, filename); ali@322: return NULL; ali@424: } ali@322: ali@322: if (fstat(fd, &st) < 0) { ali@447: razor_set_error_posix(error, filename); ali@322: close(fd); ali@322: return NULL; ali@322: } ali@322: ali@322: *length = st.st_size; ali@458: ali@322: #if HAVE_SYS_MMAN_H ali@458: ofend = open_files.data + open_files.size; ali@458: for (of = open_files.data; of < ofend; of++) ali@458: if (!(of->flags & OPEN_FILE_USED)) ali@458: break; ali@458: if (of == ofend) { ali@458: of = array_add(&open_files, sizeof *of); ali@458: of->flags = 0; ali@458: } ali@458: ali@424: if (!private) { ali@424: addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); ali@424: if (addr == MAP_FAILED) ali@424: addr = NULL; ali@458: else ali@458: of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED; ali@322: } ali@458: #endif /* HAVE_SYS_MMAN_H */ ali@424: if (!addr) { ali@424: addr = malloc(st.st_size); ali@424: if (addr) { ali@458: #if HAVE_SYS_MMAN_H ali@458: of->flags = OPEN_FILE_USED; ali@458: #endif ali@424: nb = 0; ali@424: while(nb < st.st_size) { ali@424: res = read(fd, addr + nb, st.st_size - nb); ali@424: if (res <= 0) { ali@447: razor_set_error_posix(error, filename); ali@424: free(addr); ali@424: addr = NULL; ali@424: break; ali@424: } ali@424: nb += res; ali@424: } ali@424: } else ali@447: razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, ali@447: "Not enough memory"); ali@424: } ali@322: close(fd); ali@322: ali@458: #if HAVE_SYS_MMAN_H ali@458: of->addr = addr; ali@458: of->length = st.st_size; ali@458: #endif ali@458: ali@322: return addr; ali@322: } ali@322: ali@424: int razor_file_free_contents(void *addr, size_t length) ali@322: { ali@322: #if HAVE_SYS_MMAN_H ali@458: int retval, mmapped; ali@458: struct open_file *of, *ofend; ali@458: ali@458: ofend = open_files.data + open_files.size; ali@458: for (of = open_files.data; of < ofend; of++) ali@458: if ((of->flags & OPEN_FILE_USED) && of->addr == addr) ali@458: break; ali@458: ali@458: if (of == ofend) ali@458: return 1; ali@458: ali@458: length = of->length; ali@458: mmapped = of->flags & OPEN_FILE_MMAPPED; ali@458: of->flags &= ~OPEN_FILE_USED; ali@458: ali@458: for (of = open_files.data; of < ofend; of++) ali@458: if (of->flags & OPEN_FILE_USED) ali@458: break; ali@458: ali@458: if (of == ofend) { ali@458: array_release(&open_files); ali@458: array_init(&open_files); ali@458: } ali@458: ali@458: if (mmapped) ali@458: return munmap(addr, length); ali@458: #endif ali@458: ali@322: free(addr); ali@322: return 0; ali@322: } ali@322: rhughes@241: struct qsort_context { rhughes@241: size_t size; rhughes@241: razor_compare_with_data_func_t compare; rhughes@241: void *data; rhughes@241: }; rhughes@241: rhughes@241: static void rhughes@241: qsort_swap(void *p1, void *p2, size_t size) rhughes@241: { rhughes@241: char buffer[size]; rhughes@241: ali@406: if (p1 != p2) { ali@406: memcpy(buffer, p1, size); ali@406: memcpy(p1, p2, size); ali@406: memcpy(p2, buffer, size); ali@406: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: __qsort_with_data(void *base, size_t nelem, uint32_t *map, rhughes@241: struct qsort_context *ctx) rhughes@241: { rhughes@241: void *p, *start, *end, *pivot; rhughes@241: uint32_t *mp, *mstart, *mend, tmp; rhughes@241: int left, right, result; rhughes@241: size_t size = ctx->size; rhughes@241: rhughes@241: p = base; rhughes@241: start = base; rhughes@241: end = base + nelem * size; rhughes@241: mp = map; rhughes@241: mstart = map; rhughes@241: mend = map + nelem; ali@337: pivot = base + (rand() % nelem) * size; rhughes@241: rhughes@241: while (p < end) { rhughes@241: result = ctx->compare(p, pivot, ctx->data); rhughes@241: if (result < 0) { rhughes@241: qsort_swap(p, start, size); rhughes@241: tmp = *mp; rhughes@241: *mp = *mstart; rhughes@241: *mstart = tmp; rhughes@241: if (start == pivot) rhughes@241: pivot = p; rhughes@241: start += size; rhughes@241: mstart++; rhughes@241: p += size; rhughes@241: mp++; rhughes@241: } else if (result == 0) { rhughes@241: p += size; rhughes@241: mp++; rhughes@241: } else { rhughes@241: end -= size; rhughes@241: mend--; rhughes@241: qsort_swap(p, end, size); rhughes@241: tmp = *mp; rhughes@241: *mp = *mend; rhughes@241: *mend = tmp; rhughes@241: if (end == pivot) rhughes@241: pivot = p; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: left = (start - base) / size; rhughes@241: right = (base + nelem * size - end) / size; rhughes@241: if (left > 1) rhughes@241: __qsort_with_data(base, left, map, ctx); rhughes@241: if (right > 1) rhughes@241: __qsort_with_data(end, right, mend, ctx); rhughes@241: } rhughes@241: rhughes@241: uint32_t * rhughes@241: razor_qsort_with_data(void *base, size_t nelem, size_t size, rhughes@241: razor_compare_with_data_func_t compare, void *data) rhughes@241: { rhughes@241: struct qsort_context ctx; rhughes@241: uint32_t *map; rhughes@241: int i; rhughes@241: rhughes@241: if (nelem == 0) rhughes@241: return NULL; rhughes@241: rhughes@241: ctx.size = size; rhughes@241: ctx.compare = compare; rhughes@241: ctx.data = data; rhughes@241: rhughes@241: map = malloc(nelem * sizeof (uint32_t)); rhughes@241: for (i = 0; i < nelem; i++) rhughes@241: map[i] = i; rhughes@241: rhughes@241: __qsort_with_data(base, nelem, map, &ctx); rhughes@241: rhughes@241: return map; rhughes@241: } ali@372: ali@372: void environment_init(struct environment *env) ali@372: { ali@372: env->is_set = 0; ali@372: array_init(&env->string_pool); ali@372: array_init(&env->vars); ali@372: } ali@372: ali@372: void environment_add_variable(struct environment *env, ali@372: const char *variable, const char *value) ali@372: { ali@372: char *s; ali@372: uint32_t *r; ali@372: assert(!env->is_set); ali@372: ali@372: s = array_add(&env->string_pool, ali@372: strlen(variable) + strlen(value) + 2); ali@372: sprintf(s, "%s=%s", variable, value); ali@372: r = array_add(&env->vars, sizeof *r); ali@372: *r = s - (char *)env->string_pool.data; ali@372: } ali@372: ali@372: void environment_set(struct environment *env) ali@372: { ali@372: int i, count; ali@442: char *s; ali@442: #ifndef WIN32 ali@442: char *t; ali@442: #endif ali@372: uint32_t *r; ali@372: ali@372: if (!env->is_set) { ali@372: count = env->vars.size / sizeof(uint32_t); ali@372: r = (uint32_t *)env->vars.data; ali@372: for (i = 0; i < count; i++) { ali@372: s = env->string_pool.data + *r++; ali@406: #ifdef WIN32 ali@372: putenv(s); ali@406: #else ali@406: t = strchr(s, '='); ali@406: *t = '\0'; ali@406: setenv(s, t + 1, 1); ali@406: *t = '='; ali@406: #endif ali@372: } ali@372: ali@372: env->is_set = 1; ali@372: } ali@372: } ali@372: ali@372: void environment_unset(struct environment *env) ali@372: { ali@372: int i, count; ali@372: char c, *s, *t; ali@372: uint32_t *r; ali@372: ali@372: if (env->is_set) { ali@372: count = env->vars.size / sizeof(uint32_t); ali@372: r = (uint32_t *)env->vars.data; ali@372: for (i = 0; i < count; i++) { ali@372: s = env->string_pool.data + *r++; ali@406: t = strchr(s, '='); ali@406: #ifdef WIN32 ali@406: t++; ali@372: c = *t; ali@372: *t = '\0'; ali@372: putenv(s); ali@372: *t = c; ali@406: #else ali@406: c = *t; ali@406: *t = '\0'; ali@406: unsetenv(s); ali@406: *t = c; ali@406: #endif ali@372: } ali@372: ali@372: env->is_set = 0; ali@372: } ali@372: } ali@372: ali@372: void environment_release(struct environment *env) ali@372: { ali@372: environment_unset(env); ali@372: array_release(&env->string_pool); ali@372: array_release(&env->vars); ali@372: } ali@403: ali@403: RAZOR_EXPORT char *razor_concat(const char *s, ...) ali@403: { ali@403: va_list args; ali@403: const char *string; ali@403: char *concat; ali@403: size_t n, len; ali@403: ali@403: va_start(args, s); ali@403: ali@403: len = strlen(s); ali@403: while((string = va_arg(args, const char *))) ali@403: len += strlen(string); ali@403: ali@403: va_end(args); ali@403: ali@403: concat = malloc(len + 1); ali@403: ali@403: if (!concat) ali@403: return NULL; ali@403: ali@403: va_start(args, s); ali@403: ali@403: len = strlen(s); ali@403: memcpy(concat, s, len); ali@403: n = len; ali@403: while((string = va_arg(args, const char *))) { ali@403: len = strlen(string); ali@403: memcpy(concat + n, string, len); ali@403: n += len; ali@403: } ali@403: ali@403: va_end(args); ali@403: ali@403: concat[n] = '\0'; ali@403: ali@403: return concat; ali@403: } ali@403: ali@403: RAZOR_EXPORT const char *razor_system_arch(void) ali@403: { ali@403: #ifdef MSWIN_API ali@403: SYSTEM_INFO si; ali@403: ali@403: GetNativeSystemInfo(&si); ali@403: switch(si.wProcessorArchitecture) ali@403: { ali@403: case PROCESSOR_ARCHITECTURE_INTEL: ali@403: return "i686"; ali@403: case PROCESSOR_ARCHITECTURE_AMD64: ali@403: return "x86_64"; ali@403: default: ali@403: return NULL; ali@403: } ali@403: #else ali@403: static struct utsname un; ali@403: ali@403: if (uname(&un)) ali@403: return NULL; ali@403: else ali@403: return un.machine; ali@403: #endif ali@403: } ali@416: ali@416: #ifdef MSWIN_API ali@416: ali@416: char *razor_utf16_to_utf8(const wchar_t *utf16, int len) ali@416: { ali@416: int n; ali@416: char *utf8; ali@416: ali@455: if (len == 0) ali@455: return strdup(""); ali@455: ali@416: n = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL); ali@455: if (len > 0) ali@416: n++; ali@416: utf8 = malloc(n); ali@416: (void)WideCharToMultiByte(CP_UTF8, 0, utf16, len, utf8, n, NULL, NULL); ali@455: if (len > 0) ali@416: utf8[n - 1] = 0; ali@416: ali@416: return utf8; ali@416: } ali@416: ali@416: wchar_t *razor_utf8_to_utf16(const char *utf8, int len) ali@416: { ali@416: int n; ali@416: wchar_t *utf16; ali@416: ali@455: if (len == 0) { ali@455: utf16 = calloc(1, sizeof(wchar_t)); ali@455: return utf16; ali@455: } ali@455: ali@416: n = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0); ali@455: if (len > 0) ali@416: n++; ali@416: utf16 = malloc(n * sizeof(wchar_t)); ali@416: (void)MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, n); ali@455: if (len > 0) ali@416: utf16[n - 1] = 0; ali@416: ali@416: return utf16; ali@416: } ali@416: ali@416: #endif /* MSWIN_API */