<sys/types.h> is required before <sys/sysctl.h> on FreeBSD
[wimlib] / src / util.c
1 /*
2  * util.c - utility functions
3  */
4
5 /*
6  * Copyright (C) 2012, 2013, 2014 Eric Biggers
7  *
8  * This file is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option) any
11  * later version.
12  *
13  * This file is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this file; if not, see http://www.gnu.org/licenses/.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_SYS_SYSCTL_H
31 #  include <sys/types.h>
32 #  include <sys/sysctl.h>
33 #endif
34 #include <unistd.h>
35
36 #include "wimlib.h"
37 #include "wimlib/assert.h"
38 #include "wimlib/error.h"
39 #include "wimlib/timestamp.h"
40 #include "wimlib/util.h"
41 #include "wimlib/xml.h"
42
43 /*******************
44  * Memory allocation
45  *******************/
46
47 static void *(*wimlib_malloc_func) (size_t)         = malloc;
48 static void  (*wimlib_free_func)   (void *)         = free;
49 static void *(*wimlib_realloc_func)(void *, size_t) = realloc;
50
51 void *
52 wimlib_malloc(size_t size)
53 {
54         void *ptr;
55
56 retry:
57         ptr = (*wimlib_malloc_func)(size);
58         if (unlikely(!ptr)) {
59                 if (size == 0) {
60                         size = 1;
61                         goto retry;
62                 }
63         }
64         return ptr;
65 }
66
67 void
68 wimlib_free_memory(void *ptr)
69 {
70         (*wimlib_free_func)(ptr);
71 }
72
73 void *
74 wimlib_realloc(void *ptr, size_t size)
75 {
76         if (size == 0)
77                 size = 1;
78         return (*wimlib_realloc_func)(ptr, size);
79 }
80
81 void *
82 wimlib_calloc(size_t nmemb, size_t size)
83 {
84         size_t total_size = nmemb * size;
85         void *p = MALLOC(total_size);
86         if (p)
87                 p = memset(p, 0, total_size);
88         return p;
89 }
90
91 char *
92 wimlib_strdup(const char *str)
93 {
94         size_t size;
95         char *p;
96
97         size = strlen(str);
98         p = MALLOC(size + 1);
99         if (p)
100                 p = memcpy(p, str, size + 1);
101         return p;
102 }
103
104 #ifdef __WIN32__
105 wchar_t *
106 wimlib_wcsdup(const wchar_t *str)
107 {
108         size_t size;
109         wchar_t *p;
110
111         size = wcslen(str);
112         p = MALLOC((size + 1) * sizeof(wchar_t));
113         if (p)
114                 p = wmemcpy(p, str, size + 1);
115         return p;
116 }
117 #endif
118
119 void *
120 wimlib_aligned_malloc(size_t size, size_t alignment)
121 {
122         wimlib_assert(alignment != 0 && is_power_of_2(alignment) &&
123                       alignment <= 4096);
124
125         const uintptr_t mask = alignment - 1;
126         char *ptr = NULL;
127         char *raw_ptr;
128
129         raw_ptr = MALLOC(mask + sizeof(size_t) + size);
130         if (raw_ptr) {
131                 ptr = (char *)raw_ptr + sizeof(size_t);
132                 ptr = (void *)(((uintptr_t)ptr + mask) & ~mask);
133                 *((size_t *)ptr - 1) = ptr - raw_ptr;
134         }
135         return ptr;
136 }
137
138 void
139 wimlib_aligned_free(void *ptr)
140 {
141         if (ptr)
142                 FREE((char *)ptr - *((size_t *)ptr - 1));
143 }
144
145 void *
146 memdup(const void *mem, size_t size)
147 {
148         void *ptr = MALLOC(size);
149         if (ptr)
150                 ptr = memcpy(ptr, mem, size);
151         return ptr;
152 }
153
154 /* API function documented in wimlib.h  */
155 WIMLIBAPI int
156 wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
157                             void (*free_func)(void *),
158                             void *(*realloc_func)(void *, size_t))
159 {
160         wimlib_malloc_func  = malloc_func  ? malloc_func  : malloc;
161         wimlib_free_func    = free_func    ? free_func    : free;
162         wimlib_realloc_func = realloc_func ? realloc_func : realloc;
163
164         xml_set_memory_allocator(wimlib_malloc_func, wimlib_free_func,
165                                  wimlib_realloc_func);
166         return 0;
167 }
168
169 /*******************
170  * String utilities
171  *******************/
172
173 #ifndef HAVE_MEMPCPY
174 void *mempcpy(void *dst, const void *src, size_t n)
175 {
176         return memcpy(dst, src, n) + n;
177 }
178 #endif
179
180 static bool seeded = false;
181
182 static void
183 seed_random(void)
184 {
185         srand(now_as_wim_timestamp());
186         seeded = true;
187 }
188
189 /* Fills @n characters pointed to by @p with random alphanumeric characters. */
190 void
191 randomize_char_array_with_alnum(tchar *p, size_t n)
192 {
193         if (!seeded)
194                 seed_random();
195         while (n--) {
196                 int r = rand() % 62;
197                 if (r < 26)
198                         *p++ = r + 'a';
199                 else if (r < 52)
200                         *p++ = r - 26 + 'A';
201                 else
202                         *p++ = r - 52 + '0';
203         }
204 }
205
206 /* Fills @n bytes pointer to by @p with random numbers. */
207 void
208 randomize_byte_array(u8 *p, size_t n)
209 {
210         if (!seeded)
211                 seed_random();
212         while (n--)
213                 *p++ = rand();
214 }
215
216 #ifndef __WIN32__
217 unsigned
218 get_available_cpus(void)
219 {
220         long n = sysconf(_SC_NPROCESSORS_ONLN);
221         if (n < 1 || n >= UINT_MAX) {
222                 WARNING("Failed to determine number of processors; assuming 1.");
223                 return 1;
224         }
225         return n;
226 }
227 #endif /* !__WIN32__ */
228
229 #ifndef __WIN32__
230 u64
231 get_available_memory(void)
232 {
233 #if defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
234         long page_size = sysconf(_SC_PAGESIZE);
235         long num_pages = sysconf(_SC_PHYS_PAGES);
236         if (page_size <= 0 || num_pages <= 0)
237                 goto default_size;
238         return ((u64)page_size * (u64)num_pages);
239 #else
240         int mib[2] = {CTL_HW, HW_MEMSIZE};
241         u64 memsize;
242         size_t len = sizeof(memsize);
243         if (sysctl(mib, ARRAY_LEN(mib), &memsize, &len, NULL, 0) < 0 || len != 8)
244                 goto default_size;
245         return memsize;
246 #endif
247
248 default_size:
249         WARNING("Failed to determine available memory; assuming 1 GiB");
250         return (u64)1 << 30;
251 }
252 #endif /* !__WIN32__ */