f22d451e6e8f4b4fd08c5a023dbaecb90ea62017
[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/sysctl.h>
32 #endif
33 #include <unistd.h>
34
35 #include "wimlib.h"
36 #include "wimlib/assert.h"
37 #include "wimlib/error.h"
38 #include "wimlib/timestamp.h"
39 #include "wimlib/util.h"
40 #include "wimlib/xml.h"
41
42 /*******************
43  * Memory allocation
44  *******************/
45
46 static void *(*wimlib_malloc_func) (size_t)         = malloc;
47 static void  (*wimlib_free_func)   (void *)         = free;
48 static void *(*wimlib_realloc_func)(void *, size_t) = realloc;
49
50 void *
51 wimlib_malloc(size_t size)
52 {
53         void *ptr;
54
55 retry:
56         ptr = (*wimlib_malloc_func)(size);
57         if (unlikely(!ptr)) {
58                 if (size == 0) {
59                         size = 1;
60                         goto retry;
61                 }
62         }
63         return ptr;
64 }
65
66 void
67 wimlib_free_memory(void *ptr)
68 {
69         (*wimlib_free_func)(ptr);
70 }
71
72 void *
73 wimlib_realloc(void *ptr, size_t size)
74 {
75         if (size == 0)
76                 size = 1;
77         return (*wimlib_realloc_func)(ptr, size);
78 }
79
80 void *
81 wimlib_calloc(size_t nmemb, size_t size)
82 {
83         size_t total_size = nmemb * size;
84         void *p = MALLOC(total_size);
85         if (p)
86                 p = memset(p, 0, total_size);
87         return p;
88 }
89
90 char *
91 wimlib_strdup(const char *str)
92 {
93         size_t size;
94         char *p;
95
96         size = strlen(str);
97         p = MALLOC(size + 1);
98         if (p)
99                 p = memcpy(p, str, size + 1);
100         return p;
101 }
102
103 #ifdef __WIN32__
104 wchar_t *
105 wimlib_wcsdup(const wchar_t *str)
106 {
107         size_t size;
108         wchar_t *p;
109
110         size = wcslen(str);
111         p = MALLOC((size + 1) * sizeof(wchar_t));
112         if (p)
113                 p = wmemcpy(p, str, size + 1);
114         return p;
115 }
116 #endif
117
118 void *
119 wimlib_aligned_malloc(size_t size, size_t alignment)
120 {
121         wimlib_assert(alignment != 0 && is_power_of_2(alignment) &&
122                       alignment <= 4096);
123
124         const uintptr_t mask = alignment - 1;
125         char *ptr = NULL;
126         char *raw_ptr;
127
128         raw_ptr = MALLOC(mask + sizeof(size_t) + size);
129         if (raw_ptr) {
130                 ptr = (char *)raw_ptr + sizeof(size_t);
131                 ptr = (void *)(((uintptr_t)ptr + mask) & ~mask);
132                 *((size_t *)ptr - 1) = ptr - raw_ptr;
133         }
134         return ptr;
135 }
136
137 void
138 wimlib_aligned_free(void *ptr)
139 {
140         if (ptr)
141                 FREE((char *)ptr - *((size_t *)ptr - 1));
142 }
143
144 void *
145 memdup(const void *mem, size_t size)
146 {
147         void *ptr = MALLOC(size);
148         if (ptr)
149                 ptr = memcpy(ptr, mem, size);
150         return ptr;
151 }
152
153 /* API function documented in wimlib.h  */
154 WIMLIBAPI int
155 wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
156                             void (*free_func)(void *),
157                             void *(*realloc_func)(void *, size_t))
158 {
159         wimlib_malloc_func  = malloc_func  ? malloc_func  : malloc;
160         wimlib_free_func    = free_func    ? free_func    : free;
161         wimlib_realloc_func = realloc_func ? realloc_func : realloc;
162
163         xml_set_memory_allocator(wimlib_malloc_func, wimlib_free_func,
164                                  wimlib_realloc_func);
165         return 0;
166 }
167
168 /*******************
169  * String utilities
170  *******************/
171
172 #ifndef HAVE_MEMPCPY
173 void *mempcpy(void *dst, const void *src, size_t n)
174 {
175         return memcpy(dst, src, n) + n;
176 }
177 #endif
178
179 static bool seeded = false;
180
181 static void
182 seed_random(void)
183 {
184         srand(now_as_wim_timestamp());
185         seeded = true;
186 }
187
188 /* Fills @n characters pointed to by @p with random alphanumeric characters. */
189 void
190 randomize_char_array_with_alnum(tchar *p, size_t n)
191 {
192         if (!seeded)
193                 seed_random();
194         while (n--) {
195                 int r = rand() % 62;
196                 if (r < 26)
197                         *p++ = r + 'a';
198                 else if (r < 52)
199                         *p++ = r - 26 + 'A';
200                 else
201                         *p++ = r - 52 + '0';
202         }
203 }
204
205 /* Fills @n bytes pointer to by @p with random numbers. */
206 void
207 randomize_byte_array(u8 *p, size_t n)
208 {
209         if (!seeded)
210                 seed_random();
211         while (n--)
212                 *p++ = rand();
213 }
214
215 #ifndef __WIN32__
216 unsigned
217 get_available_cpus(void)
218 {
219         long n = sysconf(_SC_NPROCESSORS_ONLN);
220         if (n < 1 || n >= UINT_MAX) {
221                 WARNING("Failed to determine number of processors; assuming 1.");
222                 return 1;
223         }
224         return n;
225 }
226 #endif /* !__WIN32__ */
227
228 #ifndef __WIN32__
229 u64
230 get_available_memory(void)
231 {
232 #if defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
233         long page_size = sysconf(_SC_PAGESIZE);
234         long num_pages = sysconf(_SC_PHYS_PAGES);
235         if (page_size <= 0 || num_pages <= 0)
236                 goto default_size;
237         return ((u64)page_size * (u64)num_pages);
238 #else
239         int mib[2] = {CTL_HW, HW_MEMSIZE};
240         u64 memsize;
241         size_t len = sizeof(memsize);
242         if (sysctl(mib, ARRAY_LEN(mib), &memsize, &len, NULL, 0) < 0 || len != 8)
243                 goto default_size;
244         return memsize;
245 #endif
246
247 default_size:
248         WARNING("Failed to determine available memory; assuming 1 GiB");
249         return (u64)1 << 30;
250 }
251 #endif /* !__WIN32__ */