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