blob: dd971e0f884b52840e0751dbe54e4e6f8d4bcda6 [file] [log] [blame]
Przemyslaw Skibinski7a8a03c2016-12-21 15:08:44 +01001/**
2 * util.h - utility functions
Sean Purcell680e4e02017-03-23 11:52:09 -07003 *
Przemyslaw Skibinski7a8a03c2016-12-21 15:08:44 +01004 * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
5 * All rights reserved.
6 *
7 * This source code is licensed under the BSD-style license found in the
8 * LICENSE file in the root directory of this source tree. An additional grant
9 * of patent rights can be found in the PATENTS file in the same directory.
10 */
inikep69fcd7c2016-04-28 12:23:33 +020011
inikep69fcd7c2016-04-28 12:23:33 +020012#ifndef UTIL_H_MODULE
13#define UTIL_H_MODULE
14
15#if defined (__cplusplus)
16extern "C" {
17#endif
18
inikep9c22e572016-05-05 11:53:42 +020019
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010020
inikep69fcd7c2016-04-28 12:23:33 +020021/*-****************************************
22* Dependencies
23******************************************/
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010024#include "platform.h" /* PLATFORM_POSIX_VERSION */
25#include <stdlib.h> /* malloc */
26#include <stddef.h> /* size_t, ptrdiff_t */
27#include <stdio.h> /* fprintf */
Sean Purcellafa48512017-04-13 12:28:28 -070028#include <string.h> /* strncmp */
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010029#include <sys/types.h> /* stat, utime */
30#include <sys/stat.h> /* stat */
Przemyslaw Skibinskib40884f2016-11-03 09:54:53 +010031#if defined(_MSC_VER)
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010032# include <sys/utime.h> /* utime */
33# include <io.h> /* _chmod */
Przemyslaw Skibinskib40884f2016-11-03 09:54:53 +010034#else
Yann Colletfda539f2016-12-12 01:03:23 +010035# include <unistd.h> /* chown, stat */
36# include <utime.h> /* utime */
Przemyslaw Skibinskib40884f2016-11-03 09:54:53 +010037#endif
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010038#include <time.h> /* time */
Przemyslaw Skibinskib40884f2016-11-03 09:54:53 +010039#include <errno.h>
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010040#include "mem.h" /* U32, U64 */
inikep69fcd7c2016-04-28 12:23:33 +020041
inikep31634032016-05-05 00:25:38 +020042
Przemyslaw Skibinski6e59b3c2017-02-15 17:03:16 +010043/* ************************************************************
44* Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW
45***************************************************************/
46#if defined(_MSC_VER) && (_MSC_VER >= 1400)
47# define UTIL_fseek _fseeki64
48#elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */
49# define UTIL_fseek fseeko
50#elif defined(__MINGW32__) && defined(__MSVCRT__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS)
51# define UTIL_fseek fseeko64
52#else
53# define UTIL_fseek fseek
54#endif
55
56
inikep9c22e572016-05-05 11:53:42 +020057/*-****************************************
58* Sleep functions: Windows - Posix - others
59******************************************/
inikep31634032016-05-05 00:25:38 +020060#if defined(_WIN32)
inikep83c76b42016-04-28 13:16:01 +020061# include <windows.h>
Przemyslaw Skibinski94abd6a2017-02-07 16:36:19 +010062# define SET_REALTIME_PRIORITY SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)
inikep83c76b42016-04-28 13:16:01 +020063# define UTIL_sleep(s) Sleep(1000*s)
64# define UTIL_sleepMilli(milli) Sleep(milli)
Przemyslaw Skibinskib0f36632016-12-16 15:41:18 +010065#elif PLATFORM_POSIX_VERSION >= 0 /* Unix-like operating system */
inikep31634032016-05-05 00:25:38 +020066# include <unistd.h>
67# include <sys/resource.h> /* setpriority */
68# include <time.h> /* clock_t, nanosleep, clock, CLOCKS_PER_SEC */
Peter (Stig) Edwards04773ac2016-05-21 12:15:48 +010069# if defined(PRIO_PROCESS)
Przemyslaw Skibinski94abd6a2017-02-07 16:36:19 +010070# define SET_REALTIME_PRIORITY setpriority(PRIO_PROCESS, 0, -20)
Peter (Stig) Edwards04773ac2016-05-21 12:15:48 +010071# else
Przemyslaw Skibinski94abd6a2017-02-07 16:36:19 +010072# define SET_REALTIME_PRIORITY /* disabled */
Peter (Stig) Edwards04773ac2016-05-21 12:15:48 +010073# endif
inikep31634032016-05-05 00:25:38 +020074# define UTIL_sleep(s) sleep(s)
Przemyslaw Skibinskib0f36632016-12-16 15:41:18 +010075# if (defined(__linux__) && (PLATFORM_POSIX_VERSION >= 199309L)) || (PLATFORM_POSIX_VERSION >= 200112L) /* nanosleep requires POSIX.1-2001 */
inikep9c22e572016-05-05 11:53:42 +020076# define UTIL_sleepMilli(milli) { struct timespec t; t.tv_sec=0; t.tv_nsec=milli*1000000ULL; nanosleep(&t, NULL); }
77# else
78# define UTIL_sleepMilli(milli) /* disabled */
79# endif
inikep83c76b42016-04-28 13:16:01 +020080#else
Przemyslaw Skibinski94abd6a2017-02-07 16:36:19 +010081# define SET_REALTIME_PRIORITY /* disabled */
inikep31634032016-05-05 00:25:38 +020082# define UTIL_sleep(s) /* disabled */
inikep83c76b42016-04-28 13:16:01 +020083# define UTIL_sleepMilli(milli) /* disabled */
inikep83c76b42016-04-28 13:16:01 +020084#endif
85
inikep31634032016-05-05 00:25:38 +020086
Przemyslaw Skibinskiead350b2016-12-21 09:04:59 +010087/* *************************************
88* Constants
89***************************************/
90#define LIST_SIZE_INCREASE (8*1024)
91
92
Przemyslaw Skibinskiead350b2016-12-21 09:04:59 +010093/*-****************************************
94* Compiler specifics
95******************************************/
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010096#if defined(__INTEL_COMPILER)
97# pragma warning(disable : 177) /* disable: message #177: function was declared but never referenced, useful with UTIL_STATIC */
98#endif
Przemyslaw Skibinskiead350b2016-12-21 09:04:59 +010099#if defined(__GNUC__)
100# define UTIL_STATIC static __attribute__((unused))
101#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
102# define UTIL_STATIC static inline
103#elif defined(_MSC_VER)
104# define UTIL_STATIC static __inline
105#else
106# define UTIL_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
107#endif
108
109
inikep31634032016-05-05 00:25:38 +0200110/*-****************************************
111* Time functions
112******************************************/
Przemyslaw Skibinski83775d92017-02-20 11:11:50 +0100113#if defined(_WIN32) /* Windows */
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100114 typedef LARGE_INTEGER UTIL_freq_t;
inikep83c76b42016-04-28 13:16:01 +0200115 typedef LARGE_INTEGER UTIL_time_t;
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100116 UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { if (!QueryPerformanceFrequency(ticksPerSecond)) fprintf(stderr, "ERROR: QueryPerformance not present\n"); }
inikepaaaf9232016-05-09 16:19:25 +0200117 UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { QueryPerformanceCounter(x); }
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100118 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; }
119 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; }
Przemyslaw Skibinskida4a0f32017-02-20 12:18:15 +0100120#elif defined(__APPLE__) && defined(__MACH__)
121 #include <mach/mach_time.h>
122 typedef mach_timebase_info_data_t UTIL_freq_t;
123 typedef U64 UTIL_time_t;
Przemyslaw Skibinski74dcd8d2017-02-21 12:22:05 +0100124 UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* rate) { mach_timebase_info(rate); }
Przemyslaw Skibinskida4a0f32017-02-20 12:18:15 +0100125 UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = mach_absolute_time(); }
126 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; }
127 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t rate, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); }
Przemyslaw Skibinski1b593332017-02-21 07:33:45 +0100128#elif (PLATFORM_POSIX_VERSION >= 200112L)
129 #include <sys/times.h> /* times */
130 typedef U64 UTIL_freq_t;
131 typedef U64 UTIL_time_t;
132 UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=sysconf(_SC_CLK_TCK); }
133 UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { struct tms junk; clock_t newTicks = (clock_t) times(&junk); (void)junk; *x = (UTIL_time_t)newTicks; }
134 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / ticksPerSecond; }
135 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / ticksPerSecond; }
cyan49735fba09f2017-01-20 12:23:30 -0800136#else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100137 typedef clock_t UTIL_freq_t;
cyan49735fba09f2017-01-20 12:23:30 -0800138 typedef clock_t UTIL_time_t;
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100139 UTIL_STATIC void UTIL_initTimer(UTIL_freq_t* ticksPerSecond) { *ticksPerSecond=0; }
cyan49735fba09f2017-01-20 12:23:30 -0800140 UTIL_STATIC void UTIL_getTime(UTIL_time_t* x) { *x = clock(); }
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100141 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
142 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_freq_t ticksPerSecond, UTIL_time_t clockStart, UTIL_time_t clockEnd) { (void)ticksPerSecond; return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
inikep83c76b42016-04-28 13:16:01 +0200143#endif
144
145
inikep83c76b42016-04-28 13:16:01 +0200146/* returns time span in microseconds */
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100147UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart, UTIL_freq_t ticksPerSecond )
inikep83c76b42016-04-28 13:16:01 +0200148{
149 UTIL_time_t clockEnd;
inikepaaaf9232016-05-09 16:19:25 +0200150 UTIL_getTime(&clockEnd);
inikep83c76b42016-04-28 13:16:01 +0200151 return UTIL_getSpanTimeMicro(ticksPerSecond, clockStart, clockEnd);
152}
153
154
Przemyslaw Skibinskie052c602017-02-20 11:27:11 +0100155UTIL_STATIC void UTIL_waitForNextTick(UTIL_freq_t ticksPerSecond)
inikep83c76b42016-04-28 13:16:01 +0200156{
157 UTIL_time_t clockStart, clockEnd;
inikepaaaf9232016-05-09 16:19:25 +0200158 UTIL_getTime(&clockStart);
Yann Collete162ace2016-05-20 11:24:35 +0200159 do {
160 UTIL_getTime(&clockEnd);
inikepd5ff2c32016-04-28 14:40:45 +0200161 } while (UTIL_getSpanTimeNano(ticksPerSecond, clockStart, clockEnd) == 0);
inikep83c76b42016-04-28 13:16:01 +0200162}
163
164
inikep31634032016-05-05 00:25:38 +0200165
166/*-****************************************
167* File functions
168******************************************/
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100169#if defined(_MSC_VER)
Nick Terrell5152fb22017-03-29 18:51:58 -0700170 #define chmod _chmod
171 typedef struct __stat64 stat_t;
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100172#else
173 typedef struct stat stat_t;
174#endif
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100175
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100176
177UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf)
178{
179 int res = 0;
180 struct utimbuf timebuf;
181
Nick Terrell5152fb22017-03-29 18:51:58 -0700182 timebuf.actime = time(NULL);
183 timebuf.modtime = statbuf->st_mtime;
184 res += utime(filename, &timebuf); /* set access and modification times */
Przemyslaw Skibinskib40884f2016-11-03 09:54:53 +0100185
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100186#if !defined(_WIN32)
187 res += chown(filename, statbuf->st_uid, statbuf->st_gid); /* Copy ownership */
188#endif
189
190 res += chmod(filename, statbuf->st_mode & 07777); /* Copy file permissions */
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100191
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100192 errno = 0;
193 return -res; /* number of errors is returned */
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100194}
195
196
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100197UTIL_STATIC int UTIL_getFileStat(const char* infilename, stat_t *statbuf)
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100198{
199 int r;
200#if defined(_MSC_VER)
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100201 r = _stat64(infilename, statbuf);
202 if (r || !(statbuf->st_mode & S_IFREG)) return 0; /* No good... */
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100203#else
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100204 r = stat(infilename, statbuf);
205 if (r || !S_ISREG(statbuf->st_mode)) return 0; /* No good... */
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100206#endif
Przemyslaw Skibinskifcf22e32016-11-02 14:08:07 +0100207 return 1;
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100208}
209
Przemyslaw Skibinski442c75f2017-02-14 09:38:51 +0100210
Yann Collet6d4fef32017-05-17 18:36:15 -0700211UTIL_STATIC int UTIL_isRegularFile(const char* infilename)
Sean Purcell0f5c95a2017-02-07 16:33:48 -0800212{
213 stat_t statbuf;
214 return UTIL_getFileStat(infilename, &statbuf); /* Only need to know whether it is a regular file */
215}
Przemyslaw Skibinskid872b642016-11-02 12:52:20 +0100216
Przemyslaw Skibinski442c75f2017-02-14 09:38:51 +0100217
218UTIL_STATIC U32 UTIL_isDirectory(const char* infilename)
219{
220 int r;
221 stat_t statbuf;
222#if defined(_MSC_VER)
223 r = _stat64(infilename, &statbuf);
224 if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
225#else
226 r = stat(infilename, &statbuf);
227 if (!r && S_ISDIR(statbuf.st_mode)) return 1;
228#endif
229 return 0;
230}
231
Sean Purcell680e4e02017-03-23 11:52:09 -0700232UTIL_STATIC U32 UTIL_isLink(const char* infilename)
233{
234#if defined(_WIN32)
235 /* no symlinks on windows */
236 (void)infilename;
237#else
238 int r;
239 stat_t statbuf;
240 r = lstat(infilename, &statbuf);
241 if (!r && S_ISLNK(statbuf.st_mode)) return 1;
242#endif
243 return 0;
244}
245
Przemyslaw Skibinski442c75f2017-02-14 09:38:51 +0100246
inikep69fcd7c2016-04-28 12:23:33 +0200247UTIL_STATIC U64 UTIL_getFileSize(const char* infilename)
248{
249 int r;
250#if defined(_MSC_VER)
Przemyslaw Skibinski35bf23c2017-02-13 13:57:29 +0100251 struct __stat64 statbuf;
inikep69fcd7c2016-04-28 12:23:33 +0200252 r = _stat64(infilename, &statbuf);
253 if (r || !(statbuf.st_mode & S_IFREG)) return 0; /* No good... */
ds7745f0c202017-02-10 18:37:57 +0100254#elif defined(__MINGW32__) && defined (__MSVCRT__)
255 struct _stati64 statbuf;
256 r = _stati64(infilename, &statbuf);
257 if (r || !(statbuf.st_mode & S_IFREG)) return 0; /* No good... */
inikep69fcd7c2016-04-28 12:23:33 +0200258#else
259 struct stat statbuf;
260 r = stat(infilename, &statbuf);
261 if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
262#endif
263 return (U64)statbuf.st_size;
264}
265
266
inikep55d047a2016-04-28 16:50:13 +0200267UTIL_STATIC U64 UTIL_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles)
268{
269 U64 total = 0;
270 unsigned n;
271 for (n=0; n<nbFiles; n++)
272 total += UTIL_getFileSize(fileNamesTable[n]);
273 return total;
274}
275
276
inikep61739312016-09-15 18:58:18 +0200277/*
278 * A modified version of realloc().
279 * If UTIL_realloc() fails the original block is freed.
280*/
281UTIL_STATIC void *UTIL_realloc(void *ptr, size_t size)
282{
283 void *newptr = realloc(ptr, size);
284 if (newptr) return newptr;
285 free(ptr);
286 return NULL;
287}
288
Sean Purcelldee08ca2017-03-23 12:09:35 -0700289static int g_utilDisplayLevel;
290#define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__)
291#define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
292
inikep31634032016-05-05 00:25:38 +0200293#ifdef _WIN32
inikep9c22e572016-05-05 11:53:42 +0200294# define UTIL_HAS_CREATEFILELIST
inikep31634032016-05-05 00:25:38 +0200295
Sean Purcell680e4e02017-03-23 11:52:09 -0700296UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
inikep31634032016-05-05 00:25:38 +0200297{
inikep1c5ba8a2016-09-13 13:13:10 +0200298 char* path;
299 int dirLength, fnameLength, pathLength, nbFiles = 0;
Przemyslaw Skibinskiacb6e572017-02-15 17:13:35 +0100300 WIN32_FIND_DATAA cFile;
inikep31634032016-05-05 00:25:38 +0200301 HANDLE hFile;
302
inikep9f25fcf2016-09-13 16:38:54 +0200303 dirLength = (int)strlen(dirName);
inikep1c5ba8a2016-09-13 13:13:10 +0200304 path = (char*) malloc(dirLength + 3);
305 if (!path) return 0;
306
307 memcpy(path, dirName, dirLength);
308 path[dirLength] = '\\';
309 path[dirLength+1] = '*';
310 path[dirLength+2] = 0;
inikep31634032016-05-05 00:25:38 +0200311
Przemyslaw Skibinskiacb6e572017-02-15 17:13:35 +0100312 hFile=FindFirstFileA(path, &cFile);
inikep31634032016-05-05 00:25:38 +0200313 if (hFile == INVALID_HANDLE_VALUE) {
314 fprintf(stderr, "Cannot open directory '%s'\n", dirName);
315 return 0;
316 }
inikep1c5ba8a2016-09-13 13:13:10 +0200317 free(path);
inikep31634032016-05-05 00:25:38 +0200318
inikep4dbf7f42016-05-11 14:11:00 +0200319 do {
inikep9f25fcf2016-09-13 16:38:54 +0200320 fnameLength = (int)strlen(cFile.cFileName);
inikep1c5ba8a2016-09-13 13:13:10 +0200321 path = (char*) malloc(dirLength + fnameLength + 2);
322 if (!path) { FindClose(hFile); return 0; }
323 memcpy(path, dirName, dirLength);
324 path[dirLength] = '\\';
325 memcpy(path+dirLength+1, cFile.cFileName, fnameLength);
326 pathLength = dirLength+1+fnameLength;
327 path[pathLength] = 0;
inikep31634032016-05-05 00:25:38 +0200328 if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
329 if (strcmp (cFile.cFileName, "..") == 0 ||
inikep4dbf7f42016-05-11 14:11:00 +0200330 strcmp (cFile.cFileName, ".") == 0) continue;
inikepe416e302016-08-24 17:32:09 +0200331
Sean Purcell680e4e02017-03-23 11:52:09 -0700332 nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */
inikep1c5ba8a2016-09-13 13:13:10 +0200333 if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
inikep31634032016-05-05 00:25:38 +0200334 }
335 else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) {
inikep4dbf7f42016-05-11 14:11:00 +0200336 if (*bufStart + *pos + pathLength >= *bufEnd) {
337 ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
inikep61739312016-09-15 18:58:18 +0200338 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
inikep4dbf7f42016-05-11 14:11:00 +0200339 *bufEnd = *bufStart + newListSize;
inikep1c5ba8a2016-09-13 13:13:10 +0200340 if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
inikep4dbf7f42016-05-11 14:11:00 +0200341 }
342 if (*bufStart + *pos + pathLength < *bufEnd) {
343 strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos));
344 *pos += pathLength + 1;
345 nbFiles++;
346 }
inikep31634032016-05-05 00:25:38 +0200347 }
inikep1c5ba8a2016-09-13 13:13:10 +0200348 free(path);
Przemyslaw Skibinskiacb6e572017-02-15 17:13:35 +0100349 } while (FindNextFileA(hFile, &cFile));
inikep31634032016-05-05 00:25:38 +0200350
351 FindClose(hFile);
352 return nbFiles;
353}
354
Przemyslaw Skibinski0b372052016-12-16 17:12:23 +0100355#elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */
inikep9c22e572016-05-05 11:53:42 +0200356# define UTIL_HAS_CREATEFILELIST
inikep31634032016-05-05 00:25:38 +0200357# include <dirent.h> /* opendir, readdir */
Przemyslaw Skibinskiead350b2016-12-21 09:04:59 +0100358# include <string.h> /* strerror, memcpy */
inikep31634032016-05-05 00:25:38 +0200359
Sean Purcell680e4e02017-03-23 11:52:09 -0700360UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
inikep31634032016-05-05 00:25:38 +0200361{
362 DIR *dir;
363 struct dirent *entry;
inikep1c5ba8a2016-09-13 13:13:10 +0200364 char* path;
365 int dirLength, fnameLength, pathLength, nbFiles = 0;
inikep31634032016-05-05 00:25:38 +0200366
inikep31634032016-05-05 00:25:38 +0200367 if (!(dir = opendir(dirName))) {
368 fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
369 return 0;
370 }
Yann Collete162ace2016-05-20 11:24:35 +0200371
inikep9f25fcf2016-09-13 16:38:54 +0200372 dirLength = (int)strlen(dirName);
inikep7bc5c6b2016-07-26 11:07:37 +0200373 errno = 0;
inikep3eabe9b2016-05-12 17:15:41 +0200374 while ((entry = readdir(dir)) != NULL) {
inikep0bd0fae2016-05-05 13:10:57 +0200375 if (strcmp (entry->d_name, "..") == 0 ||
376 strcmp (entry->d_name, ".") == 0) continue;
inikep9f25fcf2016-09-13 16:38:54 +0200377 fnameLength = (int)strlen(entry->d_name);
inikep1c5ba8a2016-09-13 13:13:10 +0200378 path = (char*) malloc(dirLength + fnameLength + 2);
379 if (!path) { closedir(dir); return 0; }
380 memcpy(path, dirName, dirLength);
Sean Purcell680e4e02017-03-23 11:52:09 -0700381
inikep1c5ba8a2016-09-13 13:13:10 +0200382 path[dirLength] = '/';
383 memcpy(path+dirLength+1, entry->d_name, fnameLength);
384 pathLength = dirLength+1+fnameLength;
385 path[pathLength] = 0;
386
Sean Purcell680e4e02017-03-23 11:52:09 -0700387 if (!followLinks && UTIL_isLink(path)) {
388 UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path);
389 continue;
390 }
391
inikep0bd0fae2016-05-05 13:10:57 +0200392 if (UTIL_isDirectory(path)) {
Sean Purcell680e4e02017-03-23 11:52:09 -0700393 nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */
inikep1c5ba8a2016-09-13 13:13:10 +0200394 if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
inikep31634032016-05-05 00:25:38 +0200395 } else {
inikep4dbf7f42016-05-11 14:11:00 +0200396 if (*bufStart + *pos + pathLength >= *bufEnd) {
397 ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
inikep61739312016-09-15 18:58:18 +0200398 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
inikep4dbf7f42016-05-11 14:11:00 +0200399 *bufEnd = *bufStart + newListSize;
inikep1c5ba8a2016-09-13 13:13:10 +0200400 if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
inikep4dbf7f42016-05-11 14:11:00 +0200401 }
402 if (*bufStart + *pos + pathLength < *bufEnd) {
403 strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos));
404 *pos += pathLength + 1;
405 nbFiles++;
406 }
inikep31634032016-05-05 00:25:38 +0200407 }
inikep1c5ba8a2016-09-13 13:13:10 +0200408 free(path);
inikepe416e302016-08-24 17:32:09 +0200409 errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */
inikep31634032016-05-05 00:25:38 +0200410 }
411
inikep7bc5c6b2016-07-26 11:07:37 +0200412 if (errno != 0) {
413 fprintf(stderr, "readdir(%s) error: %s\n", dirName, strerror(errno));
414 free(*bufStart);
415 *bufStart = NULL;
416 }
inikep31634032016-05-05 00:25:38 +0200417 closedir(dir);
418 return nbFiles;
419}
420
421#else
422
Sean Purcell680e4e02017-03-23 11:52:09 -0700423UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
inikep31634032016-05-05 00:25:38 +0200424{
inikep4dbf7f42016-05-11 14:11:00 +0200425 (void)bufStart; (void)bufEnd; (void)pos;
Przemyslaw Skibinskiead350b2016-12-21 09:04:59 +0100426 fprintf(stderr, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
inikep31634032016-05-05 00:25:38 +0200427 return 0;
428}
429
inikepe416e302016-08-24 17:32:09 +0200430#endif /* #ifdef _WIN32 */
inikep31634032016-05-05 00:25:38 +0200431
Yann Collete162ace2016-05-20 11:24:35 +0200432/*
433 * UTIL_createFileList - takes a list of files and directories (params: inputNames, inputNamesNb), scans directories,
inikep0bdb6a82016-05-13 10:52:02 +0200434 * and returns a new list of files (params: return value, allocatedBuffer, allocatedNamesNb).
435 * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer)
436 * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called.
437 */
Sean Purcell680e4e02017-03-23 11:52:09 -0700438UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, char** allocatedBuffer, unsigned* allocatedNamesNb, int followLinks)
inikep31634032016-05-05 00:25:38 +0200439{
inikep4dbf7f42016-05-11 14:11:00 +0200440 size_t pos;
inikep0bdb6a82016-05-13 10:52:02 +0200441 unsigned i, nbFiles;
Yann Colletfda539f2016-12-12 01:03:23 +0100442 char* buf = (char*)malloc(LIST_SIZE_INCREASE);
443 char* bufend = buf + LIST_SIZE_INCREASE;
inikep0bdb6a82016-05-13 10:52:02 +0200444 const char** fileTable;
inikep31634032016-05-05 00:25:38 +0200445
inikep0bdb6a82016-05-13 10:52:02 +0200446 if (!buf) return NULL;
inikep9c22e572016-05-05 11:53:42 +0200447
inikep0bdb6a82016-05-13 10:52:02 +0200448 for (i=0, pos=0, nbFiles=0; i<inputNamesNb; i++) {
inikep957823f2016-05-25 15:30:55 +0200449 if (!UTIL_isDirectory(inputNames[i])) {
Yann Colletfda539f2016-12-12 01:03:23 +0100450 size_t const len = strlen(inputNames[i]);
inikep4dbf7f42016-05-11 14:11:00 +0200451 if (buf + pos + len >= bufend) {
452 ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE;
inikep61739312016-09-15 18:58:18 +0200453 buf = (char*)UTIL_realloc(buf, newListSize);
inikep4dbf7f42016-05-11 14:11:00 +0200454 bufend = buf + newListSize;
inikep0bdb6a82016-05-13 10:52:02 +0200455 if (!buf) return NULL;
inikep4dbf7f42016-05-11 14:11:00 +0200456 }
457 if (buf + pos + len < bufend) {
458 strncpy(buf + pos, inputNames[i], bufend - (buf + pos));
459 pos += len + 1;
460 nbFiles++;
461 }
Yann Collet415251c2016-08-01 14:26:49 +0200462 } else {
Sean Purcell680e4e02017-03-23 11:52:09 -0700463 nbFiles += UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend, followLinks);
inikep0bdb6a82016-05-13 10:52:02 +0200464 if (buf == NULL) return NULL;
Yann Collet415251c2016-08-01 14:26:49 +0200465 } }
inikep31634032016-05-05 00:25:38 +0200466
inikep0bdb6a82016-05-13 10:52:02 +0200467 if (nbFiles == 0) { free(buf); return NULL; }
inikep31634032016-05-05 00:25:38 +0200468
inikep0bdb6a82016-05-13 10:52:02 +0200469 fileTable = (const char**)malloc((nbFiles+1) * sizeof(const char*));
470 if (!fileTable) { free(buf); return NULL; }
inikep31634032016-05-05 00:25:38 +0200471
Yann Colletfda539f2016-12-12 01:03:23 +0100472 for (i=0, pos=0; i<nbFiles; i++) {
inikep0bdb6a82016-05-13 10:52:02 +0200473 fileTable[i] = buf + pos;
474 pos += strlen(fileTable[i]) + 1;
inikep31634032016-05-05 00:25:38 +0200475 }
476
inikep0bdb6a82016-05-13 10:52:02 +0200477 if (buf + pos > bufend) { free(buf); free((void*)fileTable); return NULL; }
478
479 *allocatedBuffer = buf;
480 *allocatedNamesNb = nbFiles;
481
482 return fileTable;
inikep31634032016-05-05 00:25:38 +0200483}
484
485
inikep0bdb6a82016-05-13 10:52:02 +0200486UTIL_STATIC void UTIL_freeFileList(const char** filenameTable, char* allocatedBuffer)
inikep31634032016-05-05 00:25:38 +0200487{
inikep0bdb6a82016-05-13 10:52:02 +0200488 if (allocatedBuffer) free(allocatedBuffer);
489 if (filenameTable) free((void*)filenameTable);
inikep31634032016-05-05 00:25:38 +0200490}
491
Sean Purcellafa48512017-04-13 12:28:28 -0700492/* count the number of physical cores */
493#if defined(_WIN32) || defined(WIN32)
494
495#include <windows.h>
496
497typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
498
499UTIL_STATIC int UTIL_countPhysicalCores(void)
500{
Sean Purcelle4f32352017-04-13 16:34:28 -0700501 static int numPhysicalCores = 0;
Sean Purcellafa48512017-04-13 12:28:28 -0700502 if (numPhysicalCores != 0) return numPhysicalCores;
503
504 { LPFN_GLPI glpi;
505 BOOL done = FALSE;
506 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
507 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
508 DWORD returnLength = 0;
509 size_t byteOffset = 0;
510
511 glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
512 "GetLogicalProcessorInformation");
513
514 if (glpi == NULL) {
515 goto failed;
516 }
517
518 while(!done) {
519 DWORD rc = glpi(buffer, &returnLength);
520 if (FALSE == rc) {
521 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
522 if (buffer)
523 free(buffer);
524 buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
525
526 if (buffer == NULL) {
527 perror("zstd");
528 exit(1);
529 }
530 } else {
531 /* some other error */
532 goto failed;
533 }
534 } else {
535 done = TRUE;
536 }
537 }
538
Sean Purcell3b6207d2017-04-13 14:03:56 -0700539 ptr = buffer;
Sean Purcellafa48512017-04-13 12:28:28 -0700540
Sean Purcell3b6207d2017-04-13 14:03:56 -0700541 while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
542
543 if (ptr->Relationship == RelationProcessorCore) {
Sean Purcellafa48512017-04-13 12:28:28 -0700544 numPhysicalCores++;
545 }
Sean Purcell3b6207d2017-04-13 14:03:56 -0700546
547 ptr++;
548 byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
Sean Purcellafa48512017-04-13 12:28:28 -0700549 }
550
551 free(buffer);
552
553 return numPhysicalCores;
554 }
555
556failed:
557 /* try to fall back on GetSystemInfo */
Sean Purcell3b6207d2017-04-13 14:03:56 -0700558 { SYSTEM_INFO sysinfo;
559 GetSystemInfo(&sysinfo);
560 numPhysicalCores = sysinfo.dwNumberOfProcessors;
561 if (numPhysicalCores == 0) numPhysicalCores = 1; /* just in case */
562 }
Sean Purcellafa48512017-04-13 12:28:28 -0700563 return numPhysicalCores;
564}
565
566#elif defined(__APPLE__)
567
568#include <sys/sysctl.h>
569
570/* Use apple-provided syscall
571 * see: man 3 sysctl */
572UTIL_STATIC int UTIL_countPhysicalCores(void)
573{
Sean Purcelle4f32352017-04-13 16:34:28 -0700574 static S32 numPhysicalCores = 0; /* apple specifies int32_t */
Sean Purcellafa48512017-04-13 12:28:28 -0700575 if (numPhysicalCores != 0) return numPhysicalCores;
576
Sean Purcellf876f122017-04-13 12:33:45 -0700577 { size_t size = sizeof(S32);
578 int const ret = sysctlbyname("hw.physicalcpu", &numPhysicalCores, &size, NULL, 0);
Sean Purcellafa48512017-04-13 12:28:28 -0700579 if (ret != 0) {
580 if (errno == ENOENT) {
581 /* entry not present, fall back on 1 */
582 numPhysicalCores = 1;
583 } else {
584 perror("zstd: can't get number of physical cpus");
585 exit(1);
586 }
587 }
588
589 return numPhysicalCores;
590 }
591}
592
593#elif defined(__linux__)
594
595/* parse /proc/cpuinfo
596 * siblings / cpu cores should give hyperthreading ratio
597 * otherwise fall back on sysconf */
598UTIL_STATIC int UTIL_countPhysicalCores(void)
599{
Sean Purcelle4f32352017-04-13 16:34:28 -0700600 static int numPhysicalCores = 0;
Sean Purcellafa48512017-04-13 12:28:28 -0700601
602 if (numPhysicalCores != 0) return numPhysicalCores;
603
Sean Purcell9227aae2017-04-13 14:06:40 -0700604 numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
Sean Purcellafa48512017-04-13 12:28:28 -0700605 if (numPhysicalCores == -1) {
606 /* value not queryable, fall back on 1 */
607 return numPhysicalCores = 1;
608 }
609
610 /* try to determine if there's hyperthreading */
611 { FILE* const cpuinfo = fopen("/proc/cpuinfo", "r");
Yann Collet46ac9ad2017-05-15 18:15:08 -0700612#define BUF_SIZE 80
Sean Purcellafa48512017-04-13 12:28:28 -0700613 char buff[BUF_SIZE];
614
615 int siblings = 0;
616 int cpu_cores = 0;
617 int ratio = 1;
618
619 if (cpuinfo == NULL) {
620 /* fall back on the sysconf value */
621 return numPhysicalCores;
622 }
623
624 /* assume the cpu cores/siblings values will be constant across all
625 * present processors */
626 while (!feof(cpuinfo)) {
627 if (fgets(buff, BUF_SIZE, cpuinfo) != NULL) {
628 if (strncmp(buff, "siblings", 8) == 0) {
629 const char* const sep = strchr(buff, ':');
630 if (*sep == '\0') {
631 /* formatting was broken? */
632 goto failed;
633 }
634
635 siblings = atoi(sep + 1);
636 }
637 if (strncmp(buff, "cpu cores", 9) == 0) {
638 const char* const sep = strchr(buff, ':');
639 if (*sep == '\0') {
640 /* formatting was broken? */
641 goto failed;
642 }
643
644 cpu_cores = atoi(sep + 1);
645 }
646 } else if (ferror(cpuinfo)) {
647 /* fall back on the sysconf value */
648 goto failed;
649 }
650 }
651 if (siblings && cpu_cores) {
652 ratio = siblings / cpu_cores;
653 }
654failed:
655 fclose(cpuinfo);
656 return numPhysicalCores = numPhysicalCores / ratio;
657 }
658}
659
Baptiste Daroussin7dd14d02017-04-15 16:25:08 +0200660#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
661
662/* Use apple-provided syscall
663 * see: man 3 sysctl */
664UTIL_STATIC int UTIL_countPhysicalCores(void)
665{
666 static int numPhysicalCores = 0;
667
668 if (numPhysicalCores != 0) return numPhysicalCores;
669
670 numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
671 if (numPhysicalCores == -1) {
672 /* value not queryable, fall back on 1 */
673 return numPhysicalCores = 1;
674 }
675 return numPhysicalCores;
676}
677
Sean Purcellafa48512017-04-13 12:28:28 -0700678#else
679
680UTIL_STATIC int UTIL_countPhysicalCores(void)
681{
682 /* assume 1 */
683 return 1;
684}
685
686#endif
inikep31634032016-05-05 00:25:38 +0200687
inikep69fcd7c2016-04-28 12:23:33 +0200688#if defined (__cplusplus)
689}
690#endif
691
692#endif /* UTIL_H_MODULE */