xref: /freebsd/sys/contrib/zstd/programs/util.h (revision 74ca7bf1d4c7173d5575ba168bc4b5f6d181ff5a)
1 /*
2  * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under both the BSD-style license (found in the
6  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7  * in the COPYING file in the root directory of this source tree).
8  * You may select, at your option, one of the above-listed licenses.
9  */
10 
11 #ifndef UTIL_H_MODULE
12 #define UTIL_H_MODULE
13 
14 #if defined (__cplusplus)
15 extern "C" {
16 #endif
17 
18 
19 
20 /*-****************************************
21 *  Dependencies
22 ******************************************/
23 #include "platform.h"     /* PLATFORM_POSIX_VERSION */
24 #include <stdlib.h>       /* malloc */
25 #include <stddef.h>       /* size_t, ptrdiff_t */
26 #include <stdio.h>        /* fprintf */
27 #include <string.h>       /* strncmp */
28 #include <sys/types.h>    /* stat, utime */
29 #include <sys/stat.h>     /* stat */
30 #if defined(_MSC_VER)
31 #  include <sys/utime.h>  /* utime */
32 #  include <io.h>         /* _chmod */
33 #else
34 #  include <unistd.h>     /* chown, stat */
35 #  include <utime.h>      /* utime */
36 #endif
37 #include <time.h>         /* clock_t, clock, CLOCKS_PER_SEC, nanosleep */
38 #include <errno.h>
39 #include "mem.h"          /* U32, U64 */
40 
41 
42 /* ************************************************************
43 * Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW
44 ***************************************************************/
45 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
46 #   define UTIL_fseek _fseeki64
47 #elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */
48 #  define UTIL_fseek fseeko
49 #elif defined(__MINGW32__) && defined(__MSVCRT__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS)
50 #   define UTIL_fseek fseeko64
51 #else
52 #   define UTIL_fseek fseek
53 #endif
54 
55 
56 /*-****************************************
57 *  Sleep functions: Windows - Posix - others
58 ******************************************/
59 #if defined(_WIN32)
60 #  include <windows.h>
61 #  define SET_REALTIME_PRIORITY SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)
62 #  define UTIL_sleep(s) Sleep(1000*s)
63 #  define UTIL_sleepMilli(milli) Sleep(milli)
64 #elif PLATFORM_POSIX_VERSION >= 0 /* Unix-like operating system */
65 #  include <unistd.h>
66 #  include <sys/resource.h> /* setpriority */
67 #  if defined(PRIO_PROCESS)
68 #    define SET_REALTIME_PRIORITY setpriority(PRIO_PROCESS, 0, -20)
69 #  else
70 #    define SET_REALTIME_PRIORITY /* disabled */
71 #  endif
72 #  define UTIL_sleep(s) sleep(s)
73 #  if (defined(__linux__) && (PLATFORM_POSIX_VERSION >= 199309L)) || (PLATFORM_POSIX_VERSION >= 200112L)  /* nanosleep requires POSIX.1-2001 */
74 #      define UTIL_sleepMilli(milli) { struct timespec t; t.tv_sec=0; t.tv_nsec=milli*1000000ULL; nanosleep(&t, NULL); }
75 #  else
76 #      define UTIL_sleepMilli(milli) /* disabled */
77 #  endif
78 #else
79 #  define SET_REALTIME_PRIORITY      /* disabled */
80 #  define UTIL_sleep(s)          /* disabled */
81 #  define UTIL_sleepMilli(milli) /* disabled */
82 #endif
83 
84 
85 /* *************************************
86 *  Constants
87 ***************************************/
88 #define LIST_SIZE_INCREASE   (8*1024)
89 
90 
91 /*-****************************************
92 *  Compiler specifics
93 ******************************************/
94 #if defined(__INTEL_COMPILER)
95 #  pragma warning(disable : 177)    /* disable: message #177: function was declared but never referenced, useful with UTIL_STATIC */
96 #endif
97 #if defined(__GNUC__)
98 #  define UTIL_STATIC static __attribute__((unused))
99 #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
100 #  define UTIL_STATIC static inline
101 #elif defined(_MSC_VER)
102 #  define UTIL_STATIC static __inline
103 #else
104 #  define UTIL_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */
105 #endif
106 
107 
108 /*-****************************************
109 *  Console log
110 ******************************************/
111 static int g_utilDisplayLevel;
112 #define UTIL_DISPLAY(...)         fprintf(stderr, __VA_ARGS__)
113 #define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
114 
115 
116 /*-****************************************
117 *  Time functions
118 ******************************************/
119 #if defined(_WIN32)   /* Windows */
120     #define UTIL_TIME_INITIALIZER { { 0, 0 } }
121     typedef LARGE_INTEGER UTIL_time_t;
122     UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; }
123     UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
124     {
125         static LARGE_INTEGER ticksPerSecond;
126         static int init = 0;
127         if (!init) {
128             if (!QueryPerformanceFrequency(&ticksPerSecond))
129                 UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n");
130             init = 1;
131         }
132         return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
133     }
134     UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd)
135     {
136         static LARGE_INTEGER ticksPerSecond;
137         static int init = 0;
138         if (!init) {
139             if (!QueryPerformanceFrequency(&ticksPerSecond))
140                 UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n");
141             init = 1;
142         }
143         return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
144     }
145 
146 #elif defined(__APPLE__) && defined(__MACH__)
147 
148     #include <mach/mach_time.h>
149     #define UTIL_TIME_INITIALIZER 0
150     typedef U64 UTIL_time_t;
151     UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); }
152     UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
153     {
154         static mach_timebase_info_data_t rate;
155         static int init = 0;
156         if (!init) {
157             mach_timebase_info(&rate);
158             init = 1;
159         }
160         return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL;
161     }
162     UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd)
163     {
164         static mach_timebase_info_data_t rate;
165         static int init = 0;
166         if (!init) {
167             mach_timebase_info(&rate);
168             init = 1;
169         }
170         return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom);
171     }
172 
173 #elif (PLATFORM_POSIX_VERSION >= 200112L) && (defined __UCLIBC__ || ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2))
174 
175     #define UTIL_TIME_INITIALIZER { 0, 0 }
176     typedef struct timespec UTIL_freq_t;
177     typedef struct timespec UTIL_time_t;
178     UTIL_STATIC UTIL_time_t UTIL_getTime(void)
179     {
180         UTIL_time_t time;
181         if (clock_gettime(CLOCK_MONOTONIC, &time))
182             UTIL_DISPLAYLEVEL(1, "ERROR: Failed to get time\n");   /* we could also exit() */
183         return time;
184     }
185     UTIL_STATIC UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end)
186     {
187         UTIL_time_t diff;
188         if (end.tv_nsec < begin.tv_nsec) {
189             diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec;
190             diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec;
191         } else {
192             diff.tv_sec = end.tv_sec - begin.tv_sec;
193             diff.tv_nsec = end.tv_nsec - begin.tv_nsec;
194         }
195         return diff;
196     }
197     UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end)
198     {
199         UTIL_time_t const diff = UTIL_getSpanTime(begin, end);
200         U64 micro = 0;
201         micro += 1000000ULL * diff.tv_sec;
202         micro += diff.tv_nsec / 1000ULL;
203         return micro;
204     }
205     UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end)
206     {
207         UTIL_time_t const diff = UTIL_getSpanTime(begin, end);
208         U64 nano = 0;
209         nano += 1000000000ULL * diff.tv_sec;
210         nano += diff.tv_nsec;
211         return nano;
212     }
213 #else   /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */
214     typedef clock_t UTIL_time_t;
215     #define UTIL_TIME_INITIALIZER 0
216     UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return clock(); }
217     UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
218     UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
219 #endif
220 
221 #define SEC_TO_MICRO 1000000
222 
223 /* returns time span in microseconds */
224 UTIL_STATIC U64 UTIL_clockSpanMicro(UTIL_time_t clockStart )
225 {
226     UTIL_time_t const clockEnd = UTIL_getTime();
227     return UTIL_getSpanTimeMicro(clockStart, clockEnd);
228 }
229 
230 /* returns time span in microseconds */
231 UTIL_STATIC U64 UTIL_clockSpanNano(UTIL_time_t clockStart )
232 {
233     UTIL_time_t const clockEnd = UTIL_getTime();
234     return UTIL_getSpanTimeNano(clockStart, clockEnd);
235 }
236 
237 UTIL_STATIC void UTIL_waitForNextTick(void)
238 {
239     UTIL_time_t const clockStart = UTIL_getTime();
240     UTIL_time_t clockEnd;
241     do {
242         clockEnd = UTIL_getTime();
243     } while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0);
244 }
245 
246 
247 
248 /*-****************************************
249 *  File functions
250 ******************************************/
251 #if defined(_MSC_VER)
252     #define chmod _chmod
253     typedef struct __stat64 stat_t;
254 #else
255     typedef struct stat stat_t;
256 #endif
257 
258 
259 UTIL_STATIC int UTIL_isRegularFile(const char* infilename);
260 
261 
262 UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf)
263 {
264     int res = 0;
265     struct utimbuf timebuf;
266 
267     if (!UTIL_isRegularFile(filename))
268         return -1;
269 
270     timebuf.actime = time(NULL);
271     timebuf.modtime = statbuf->st_mtime;
272     res += utime(filename, &timebuf);  /* set access and modification times */
273 
274 #if !defined(_WIN32)
275     res += chown(filename, statbuf->st_uid, statbuf->st_gid);  /* Copy ownership */
276 #endif
277 
278     res += chmod(filename, statbuf->st_mode & 07777);  /* Copy file permissions */
279 
280     errno = 0;
281     return -res; /* number of errors is returned */
282 }
283 
284 
285 UTIL_STATIC int UTIL_getFileStat(const char* infilename, stat_t *statbuf)
286 {
287     int r;
288 #if defined(_MSC_VER)
289     r = _stat64(infilename, statbuf);
290     if (r || !(statbuf->st_mode & S_IFREG)) return 0;   /* No good... */
291 #else
292     r = stat(infilename, statbuf);
293     if (r || !S_ISREG(statbuf->st_mode)) return 0;   /* No good... */
294 #endif
295     return 1;
296 }
297 
298 
299 UTIL_STATIC int UTIL_isRegularFile(const char* infilename)
300 {
301     stat_t statbuf;
302     return UTIL_getFileStat(infilename, &statbuf); /* Only need to know whether it is a regular file */
303 }
304 
305 
306 UTIL_STATIC U32 UTIL_isDirectory(const char* infilename)
307 {
308     int r;
309     stat_t statbuf;
310 #if defined(_MSC_VER)
311     r = _stat64(infilename, &statbuf);
312     if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
313 #else
314     r = stat(infilename, &statbuf);
315     if (!r && S_ISDIR(statbuf.st_mode)) return 1;
316 #endif
317     return 0;
318 }
319 
320 UTIL_STATIC U32 UTIL_isLink(const char* infilename)
321 {
322 #if defined(_WIN32)
323     /* no symlinks on windows */
324     (void)infilename;
325 #else
326     int r;
327     stat_t statbuf;
328     r = lstat(infilename, &statbuf);
329     if (!r && S_ISLNK(statbuf.st_mode)) return 1;
330 #endif
331     return 0;
332 }
333 
334 
335 #define UTIL_FILESIZE_UNKNOWN  ((U64)(-1))
336 UTIL_STATIC U64 UTIL_getFileSize(const char* infilename)
337 {
338     if (!UTIL_isRegularFile(infilename)) return UTIL_FILESIZE_UNKNOWN;
339     {   int r;
340 #if defined(_MSC_VER)
341         struct __stat64 statbuf;
342         r = _stat64(infilename, &statbuf);
343         if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
344 #elif defined(__MINGW32__) && defined (__MSVCRT__)
345         struct _stati64 statbuf;
346         r = _stati64(infilename, &statbuf);
347         if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
348 #else
349         struct stat statbuf;
350         r = stat(infilename, &statbuf);
351         if (r || !S_ISREG(statbuf.st_mode)) return UTIL_FILESIZE_UNKNOWN;
352 #endif
353         return (U64)statbuf.st_size;
354     }
355 }
356 
357 
358 UTIL_STATIC U64 UTIL_getTotalFileSize(const char* const * const fileNamesTable, unsigned nbFiles)
359 {
360     U64 total = 0;
361     int error = 0;
362     unsigned n;
363     for (n=0; n<nbFiles; n++) {
364         U64 const size = UTIL_getFileSize(fileNamesTable[n]);
365         error |= (size == UTIL_FILESIZE_UNKNOWN);
366         total += size;
367     }
368     return error ? UTIL_FILESIZE_UNKNOWN : total;
369 }
370 
371 
372 /*
373  * A modified version of realloc().
374  * If UTIL_realloc() fails the original block is freed.
375 */
376 UTIL_STATIC void *UTIL_realloc(void *ptr, size_t size)
377 {
378     void *newptr = realloc(ptr, size);
379     if (newptr) return newptr;
380     free(ptr);
381     return NULL;
382 }
383 
384 #ifdef _WIN32
385 #  define UTIL_HAS_CREATEFILELIST
386 
387 UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
388 {
389     char* path;
390     int dirLength, fnameLength, pathLength, nbFiles = 0;
391     WIN32_FIND_DATAA cFile;
392     HANDLE hFile;
393 
394     dirLength = (int)strlen(dirName);
395     path = (char*) malloc(dirLength + 3);
396     if (!path) return 0;
397 
398     memcpy(path, dirName, dirLength);
399     path[dirLength] = '\\';
400     path[dirLength+1] = '*';
401     path[dirLength+2] = 0;
402 
403     hFile=FindFirstFileA(path, &cFile);
404     if (hFile == INVALID_HANDLE_VALUE) {
405         UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName);
406         return 0;
407     }
408     free(path);
409 
410     do {
411         fnameLength = (int)strlen(cFile.cFileName);
412         path = (char*) malloc(dirLength + fnameLength + 2);
413         if (!path) { FindClose(hFile); return 0; }
414         memcpy(path, dirName, dirLength);
415         path[dirLength] = '\\';
416         memcpy(path+dirLength+1, cFile.cFileName, fnameLength);
417         pathLength = dirLength+1+fnameLength;
418         path[pathLength] = 0;
419         if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
420             if (strcmp (cFile.cFileName, "..") == 0 ||
421                 strcmp (cFile.cFileName, ".") == 0) continue;
422 
423             nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks);  /* Recursively call "UTIL_prepareFileList" with the new path. */
424             if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
425         }
426         else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) {
427             if (*bufStart + *pos + pathLength >= *bufEnd) {
428                 ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
429                 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
430                 *bufEnd = *bufStart + newListSize;
431                 if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
432             }
433             if (*bufStart + *pos + pathLength < *bufEnd) {
434                 strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos));
435                 *pos += pathLength + 1;
436                 nbFiles++;
437             }
438         }
439         free(path);
440     } while (FindNextFileA(hFile, &cFile));
441 
442     FindClose(hFile);
443     return nbFiles;
444 }
445 
446 #elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L)  /* opendir, readdir require POSIX.1-2001 */
447 #  define UTIL_HAS_CREATEFILELIST
448 #  include <dirent.h>       /* opendir, readdir */
449 #  include <string.h>       /* strerror, memcpy */
450 
451 UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
452 {
453     DIR *dir;
454     struct dirent *entry;
455     char* path;
456     int dirLength, fnameLength, pathLength, nbFiles = 0;
457 
458     if (!(dir = opendir(dirName))) {
459         UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
460         return 0;
461     }
462 
463     dirLength = (int)strlen(dirName);
464     errno = 0;
465     while ((entry = readdir(dir)) != NULL) {
466         if (strcmp (entry->d_name, "..") == 0 ||
467             strcmp (entry->d_name, ".") == 0) continue;
468         fnameLength = (int)strlen(entry->d_name);
469         path = (char*) malloc(dirLength + fnameLength + 2);
470         if (!path) { closedir(dir); return 0; }
471         memcpy(path, dirName, dirLength);
472 
473         path[dirLength] = '/';
474         memcpy(path+dirLength+1, entry->d_name, fnameLength);
475         pathLength = dirLength+1+fnameLength;
476         path[pathLength] = 0;
477 
478         if (!followLinks && UTIL_isLink(path)) {
479             UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path);
480             continue;
481         }
482 
483         if (UTIL_isDirectory(path)) {
484             nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks);  /* Recursively call "UTIL_prepareFileList" with the new path. */
485             if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
486         } else {
487             if (*bufStart + *pos + pathLength >= *bufEnd) {
488                 ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
489                 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
490                 *bufEnd = *bufStart + newListSize;
491                 if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
492             }
493             if (*bufStart + *pos + pathLength < *bufEnd) {
494                 strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos));
495                 *pos += pathLength + 1;
496                 nbFiles++;
497             }
498         }
499         free(path);
500         errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */
501     }
502 
503     if (errno != 0) {
504         UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s\n", dirName, strerror(errno));
505         free(*bufStart);
506         *bufStart = NULL;
507     }
508     closedir(dir);
509     return nbFiles;
510 }
511 
512 #else
513 
514 UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
515 {
516     (void)bufStart; (void)bufEnd; (void)pos;
517     UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
518     return 0;
519 }
520 
521 #endif /* #ifdef _WIN32 */
522 
523 /*
524  * UTIL_createFileList - takes a list of files and directories (params: inputNames, inputNamesNb), scans directories,
525  *                       and returns a new list of files (params: return value, allocatedBuffer, allocatedNamesNb).
526  * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer)
527  * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called.
528  */
529 UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, char** allocatedBuffer, unsigned* allocatedNamesNb, int followLinks)
530 {
531     size_t pos;
532     unsigned i, nbFiles;
533     char* buf = (char*)malloc(LIST_SIZE_INCREASE);
534     char* bufend = buf + LIST_SIZE_INCREASE;
535     const char** fileTable;
536 
537     if (!buf) return NULL;
538 
539     for (i=0, pos=0, nbFiles=0; i<inputNamesNb; i++) {
540         if (!UTIL_isDirectory(inputNames[i])) {
541             size_t const len = strlen(inputNames[i]);
542             if (buf + pos + len >= bufend) {
543                 ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE;
544                 buf = (char*)UTIL_realloc(buf, newListSize);
545                 bufend = buf + newListSize;
546                 if (!buf) return NULL;
547             }
548             if (buf + pos + len < bufend) {
549                 strncpy(buf + pos, inputNames[i], bufend - (buf + pos));
550                 pos += len + 1;
551                 nbFiles++;
552             }
553         } else {
554             nbFiles += UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend, followLinks);
555             if (buf == NULL) return NULL;
556     }   }
557 
558     if (nbFiles == 0) { free(buf); return NULL; }
559 
560     fileTable = (const char**)malloc((nbFiles+1) * sizeof(const char*));
561     if (!fileTable) { free(buf); return NULL; }
562 
563     for (i=0, pos=0; i<nbFiles; i++) {
564         fileTable[i] = buf + pos;
565         pos += strlen(fileTable[i]) + 1;
566     }
567 
568     if (buf + pos > bufend) { free(buf); free((void*)fileTable); return NULL; }
569 
570     *allocatedBuffer = buf;
571     *allocatedNamesNb = nbFiles;
572 
573     return fileTable;
574 }
575 
576 
577 UTIL_STATIC void UTIL_freeFileList(const char** filenameTable, char* allocatedBuffer)
578 {
579     if (allocatedBuffer) free(allocatedBuffer);
580     if (filenameTable) free((void*)filenameTable);
581 }
582 
583 /* count the number of physical cores */
584 #if defined(_WIN32) || defined(WIN32)
585 
586 #include <windows.h>
587 
588 typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
589 
590 UTIL_STATIC int UTIL_countPhysicalCores(void)
591 {
592     static int numPhysicalCores = 0;
593     if (numPhysicalCores != 0) return numPhysicalCores;
594 
595     {   LPFN_GLPI glpi;
596         BOOL done = FALSE;
597         PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
598         PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
599         DWORD returnLength = 0;
600         size_t byteOffset = 0;
601 
602         glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
603                                          "GetLogicalProcessorInformation");
604 
605         if (glpi == NULL) {
606             goto failed;
607         }
608 
609         while(!done) {
610             DWORD rc = glpi(buffer, &returnLength);
611             if (FALSE == rc) {
612                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
613                     if (buffer)
614                         free(buffer);
615                     buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
616 
617                     if (buffer == NULL) {
618                         perror("zstd");
619                         exit(1);
620                     }
621                 } else {
622                     /* some other error */
623                     goto failed;
624                 }
625             } else {
626                 done = TRUE;
627             }
628         }
629 
630         ptr = buffer;
631 
632         while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
633 
634             if (ptr->Relationship == RelationProcessorCore) {
635                 numPhysicalCores++;
636             }
637 
638             ptr++;
639             byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
640         }
641 
642         free(buffer);
643 
644         return numPhysicalCores;
645     }
646 
647 failed:
648     /* try to fall back on GetSystemInfo */
649     {   SYSTEM_INFO sysinfo;
650         GetSystemInfo(&sysinfo);
651         numPhysicalCores = sysinfo.dwNumberOfProcessors;
652         if (numPhysicalCores == 0) numPhysicalCores = 1; /* just in case */
653     }
654     return numPhysicalCores;
655 }
656 
657 #elif defined(__APPLE__)
658 
659 #include <sys/sysctl.h>
660 
661 /* Use apple-provided syscall
662  * see: man 3 sysctl */
663 UTIL_STATIC int UTIL_countPhysicalCores(void)
664 {
665     static S32 numPhysicalCores = 0; /* apple specifies int32_t */
666     if (numPhysicalCores != 0) return numPhysicalCores;
667 
668     {   size_t size = sizeof(S32);
669         int const ret = sysctlbyname("hw.physicalcpu", &numPhysicalCores, &size, NULL, 0);
670         if (ret != 0) {
671             if (errno == ENOENT) {
672                 /* entry not present, fall back on 1 */
673                 numPhysicalCores = 1;
674             } else {
675                 perror("zstd: can't get number of physical cpus");
676                 exit(1);
677             }
678         }
679 
680         return numPhysicalCores;
681     }
682 }
683 
684 #elif defined(__linux__)
685 
686 /* parse /proc/cpuinfo
687  * siblings / cpu cores should give hyperthreading ratio
688  * otherwise fall back on sysconf */
689 UTIL_STATIC int UTIL_countPhysicalCores(void)
690 {
691     static int numPhysicalCores = 0;
692 
693     if (numPhysicalCores != 0) return numPhysicalCores;
694 
695     numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
696     if (numPhysicalCores == -1) {
697         /* value not queryable, fall back on 1 */
698         return numPhysicalCores = 1;
699     }
700 
701     /* try to determine if there's hyperthreading */
702     {   FILE* const cpuinfo = fopen("/proc/cpuinfo", "r");
703 #define BUF_SIZE 80
704         char buff[BUF_SIZE];
705 
706         int siblings = 0;
707         int cpu_cores = 0;
708         int ratio = 1;
709 
710         if (cpuinfo == NULL) {
711             /* fall back on the sysconf value */
712             return numPhysicalCores;
713         }
714 
715         /* assume the cpu cores/siblings values will be constant across all
716          * present processors */
717         while (!feof(cpuinfo)) {
718             if (fgets(buff, BUF_SIZE, cpuinfo) != NULL) {
719                 if (strncmp(buff, "siblings", 8) == 0) {
720                     const char* const sep = strchr(buff, ':');
721                     if (*sep == '\0') {
722                         /* formatting was broken? */
723                         goto failed;
724                     }
725 
726                     siblings = atoi(sep + 1);
727                 }
728                 if (strncmp(buff, "cpu cores", 9) == 0) {
729                     const char* const sep = strchr(buff, ':');
730                     if (*sep == '\0') {
731                         /* formatting was broken? */
732                         goto failed;
733                     }
734 
735                     cpu_cores = atoi(sep + 1);
736                 }
737             } else if (ferror(cpuinfo)) {
738                 /* fall back on the sysconf value */
739                 goto failed;
740             }
741         }
742         if (siblings && cpu_cores) {
743             ratio = siblings / cpu_cores;
744         }
745 failed:
746         fclose(cpuinfo);
747         return numPhysicalCores = numPhysicalCores / ratio;
748     }
749 }
750 
751 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
752 
753 /* Use apple-provided syscall
754  * see: man 3 sysctl */
755 UTIL_STATIC int UTIL_countPhysicalCores(void)
756 {
757     static int numPhysicalCores = 0;
758 
759     if (numPhysicalCores != 0) return numPhysicalCores;
760 
761     numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
762     if (numPhysicalCores == -1) {
763         /* value not queryable, fall back on 1 */
764         return numPhysicalCores = 1;
765     }
766     return numPhysicalCores;
767 }
768 
769 #else
770 
771 UTIL_STATIC int UTIL_countPhysicalCores(void)
772 {
773     /* assume 1 */
774     return 1;
775 }
776 
777 #endif
778 
779 #if defined (__cplusplus)
780 }
781 #endif
782 
783 #endif /* UTIL_H_MODULE */
784