1a0483764SConrad Meyer /*
2*5ff13fbcSAllan Jude * Copyright (c) Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
3a0483764SConrad Meyer * All rights reserved.
4a0483764SConrad Meyer *
5a0483764SConrad Meyer * This source code is licensed under both the BSD-style license (found in the
6a0483764SConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7a0483764SConrad Meyer * in the COPYING file in the root directory of this source tree).
8a0483764SConrad Meyer * You may select, at your option, one of the above-listed licenses.
9a0483764SConrad Meyer */
10a0483764SConrad Meyer
11a0483764SConrad Meyer #if defined (__cplusplus)
12a0483764SConrad Meyer extern "C" {
13a0483764SConrad Meyer #endif
14a0483764SConrad Meyer
15a0483764SConrad Meyer
16a0483764SConrad Meyer /*-****************************************
17a0483764SConrad Meyer * Dependencies
18a0483764SConrad Meyer ******************************************/
19a0483764SConrad Meyer #include "util.h" /* note : ensure that platform.h is included first ! */
2037f1f268SConrad Meyer #include <stdlib.h> /* malloc, realloc, free */
2137f1f268SConrad Meyer #include <stdio.h> /* fprintf */
2237f1f268SConrad Meyer #include <time.h> /* clock_t, clock, CLOCKS_PER_SEC, nanosleep */
23a0483764SConrad Meyer #include <errno.h>
24a0483764SConrad Meyer #include <assert.h>
25a0483764SConrad Meyer
2637f1f268SConrad Meyer #if defined(_WIN32)
2737f1f268SConrad Meyer # include <sys/utime.h> /* utime */
2837f1f268SConrad Meyer # include <io.h> /* _chmod */
2937f1f268SConrad Meyer #else
3037f1f268SConrad Meyer # include <unistd.h> /* chown, stat */
31f7cd7fe5SConrad Meyer # if PLATFORM_POSIX_VERSION < 200809L || !defined(st_mtime)
3237f1f268SConrad Meyer # include <utime.h> /* utime */
3337f1f268SConrad Meyer # else
3437f1f268SConrad Meyer # include <fcntl.h> /* AT_FDCWD */
3537f1f268SConrad Meyer # include <sys/stat.h> /* utimensat */
3637f1f268SConrad Meyer # endif
3737f1f268SConrad Meyer #endif
3837f1f268SConrad Meyer
399cbefe25SConrad Meyer #if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
409cbefe25SConrad Meyer #include <direct.h> /* needed for _mkdir in windows */
419cbefe25SConrad Meyer #endif
42a0483764SConrad Meyer
4337f1f268SConrad Meyer #if defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */
4437f1f268SConrad Meyer # include <dirent.h> /* opendir, readdir */
4537f1f268SConrad Meyer # include <string.h> /* strerror, memcpy */
4637f1f268SConrad Meyer #endif /* #ifdef _WIN32 */
4737f1f268SConrad Meyer
4837f1f268SConrad Meyer /*-****************************************
4937f1f268SConrad Meyer * Internal Macros
5037f1f268SConrad Meyer ******************************************/
5137f1f268SConrad Meyer
5237f1f268SConrad Meyer /* CONTROL is almost like an assert(), but is never disabled.
5337f1f268SConrad Meyer * It's designed for failures that may happen rarely,
5437f1f268SConrad Meyer * but we don't want to maintain a specific error code path for them,
5537f1f268SConrad Meyer * such as a malloc() returning NULL for example.
5637f1f268SConrad Meyer * Since it's always active, this macro can trigger side effects.
5737f1f268SConrad Meyer */
5837f1f268SConrad Meyer #define CONTROL(c) { \
5937f1f268SConrad Meyer if (!(c)) { \
6037f1f268SConrad Meyer UTIL_DISPLAYLEVEL(1, "Error : %s, %i : %s", \
6137f1f268SConrad Meyer __FILE__, __LINE__, #c); \
6237f1f268SConrad Meyer exit(1); \
6337f1f268SConrad Meyer } }
6437f1f268SConrad Meyer
6537f1f268SConrad Meyer /* console log */
6637f1f268SConrad Meyer #define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__)
6737f1f268SConrad Meyer #define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
6837f1f268SConrad Meyer
6937f1f268SConrad Meyer /* A modified version of realloc().
7037f1f268SConrad Meyer * If UTIL_realloc() fails the original block is freed.
7137f1f268SConrad Meyer */
UTIL_realloc(void * ptr,size_t size)7237f1f268SConrad Meyer UTIL_STATIC void* UTIL_realloc(void *ptr, size_t size)
7337f1f268SConrad Meyer {
7437f1f268SConrad Meyer void *newptr = realloc(ptr, size);
7537f1f268SConrad Meyer if (newptr) return newptr;
7637f1f268SConrad Meyer free(ptr);
7737f1f268SConrad Meyer return NULL;
7837f1f268SConrad Meyer }
7937f1f268SConrad Meyer
8037f1f268SConrad Meyer #if defined(_MSC_VER)
8137f1f268SConrad Meyer #define chmod _chmod
8237f1f268SConrad Meyer #endif
8337f1f268SConrad Meyer
8437f1f268SConrad Meyer
8537f1f268SConrad Meyer /*-****************************************
8637f1f268SConrad Meyer * Console log
8737f1f268SConrad Meyer ******************************************/
8837f1f268SConrad Meyer int g_utilDisplayLevel;
8937f1f268SConrad Meyer
UTIL_requireUserConfirmation(const char * prompt,const char * abortMsg,const char * acceptableLetters,int hasStdinInput)90f7cd7fe5SConrad Meyer int UTIL_requireUserConfirmation(const char* prompt, const char* abortMsg,
91f7cd7fe5SConrad Meyer const char* acceptableLetters, int hasStdinInput) {
92f7cd7fe5SConrad Meyer int ch, result;
93f7cd7fe5SConrad Meyer
94f7cd7fe5SConrad Meyer if (hasStdinInput) {
95f7cd7fe5SConrad Meyer UTIL_DISPLAY("stdin is an input - not proceeding.\n");
96f7cd7fe5SConrad Meyer return 1;
97f7cd7fe5SConrad Meyer }
98f7cd7fe5SConrad Meyer
99f7cd7fe5SConrad Meyer UTIL_DISPLAY("%s", prompt);
100f7cd7fe5SConrad Meyer ch = getchar();
101f7cd7fe5SConrad Meyer result = 0;
102f7cd7fe5SConrad Meyer if (strchr(acceptableLetters, ch) == NULL) {
103f7cd7fe5SConrad Meyer UTIL_DISPLAY("%s", abortMsg);
104f7cd7fe5SConrad Meyer result = 1;
105f7cd7fe5SConrad Meyer }
106f7cd7fe5SConrad Meyer /* flush the rest */
107f7cd7fe5SConrad Meyer while ((ch!=EOF) && (ch!='\n'))
108f7cd7fe5SConrad Meyer ch = getchar();
109f7cd7fe5SConrad Meyer return result;
110f7cd7fe5SConrad Meyer }
111f7cd7fe5SConrad Meyer
11237f1f268SConrad Meyer
11337f1f268SConrad Meyer /*-*************************************
11437f1f268SConrad Meyer * Constants
11537f1f268SConrad Meyer ***************************************/
11637f1f268SConrad Meyer #define LIST_SIZE_INCREASE (8*1024)
11737f1f268SConrad Meyer #define MAX_FILE_OF_FILE_NAMES_SIZE (1<<20)*50
11837f1f268SConrad Meyer
11937f1f268SConrad Meyer
12037f1f268SConrad Meyer /*-*************************************
12137f1f268SConrad Meyer * Functions
12237f1f268SConrad Meyer ***************************************/
12337f1f268SConrad Meyer
UTIL_stat(const char * filename,stat_t * statbuf)124f7cd7fe5SConrad Meyer int UTIL_stat(const char* filename, stat_t* statbuf)
125a0483764SConrad Meyer {
126a0483764SConrad Meyer #if defined(_MSC_VER)
127f7cd7fe5SConrad Meyer return !_stat64(filename, statbuf);
128f7cd7fe5SConrad Meyer #elif defined(__MINGW32__) && defined (__MSVCRT__)
129f7cd7fe5SConrad Meyer return !_stati64(filename, statbuf);
130a0483764SConrad Meyer #else
131f7cd7fe5SConrad Meyer return !stat(filename, statbuf);
132a0483764SConrad Meyer #endif
133a0483764SConrad Meyer }
134a0483764SConrad Meyer
UTIL_isRegularFile(const char * infilename)135a0483764SConrad Meyer int UTIL_isRegularFile(const char* infilename)
136a0483764SConrad Meyer {
137a0483764SConrad Meyer stat_t statbuf;
138f7cd7fe5SConrad Meyer return UTIL_stat(infilename, &statbuf) && UTIL_isRegularFileStat(&statbuf);
139a0483764SConrad Meyer }
140a0483764SConrad Meyer
UTIL_isRegularFileStat(const stat_t * statbuf)141f7cd7fe5SConrad Meyer int UTIL_isRegularFileStat(const stat_t* statbuf)
142a0483764SConrad Meyer {
143a0483764SConrad Meyer #if defined(_MSC_VER)
144f7cd7fe5SConrad Meyer return (statbuf->st_mode & S_IFREG) != 0;
145a0483764SConrad Meyer #else
146f7cd7fe5SConrad Meyer return S_ISREG(statbuf->st_mode) != 0;
147a0483764SConrad Meyer #endif
148a0483764SConrad Meyer }
149a0483764SConrad Meyer
15037f1f268SConrad Meyer /* like chmod, but avoid changing permission of /dev/null */
UTIL_chmod(char const * filename,const stat_t * statbuf,mode_t permissions)151f7cd7fe5SConrad Meyer int UTIL_chmod(char const* filename, const stat_t* statbuf, mode_t permissions)
15237f1f268SConrad Meyer {
153f7cd7fe5SConrad Meyer stat_t localStatBuf;
154f7cd7fe5SConrad Meyer if (statbuf == NULL) {
155f7cd7fe5SConrad Meyer if (!UTIL_stat(filename, &localStatBuf)) return 0;
156f7cd7fe5SConrad Meyer statbuf = &localStatBuf;
157f7cd7fe5SConrad Meyer }
158f7cd7fe5SConrad Meyer if (!UTIL_isRegularFileStat(statbuf)) return 0; /* pretend success, but don't change anything */
15937f1f268SConrad Meyer return chmod(filename, permissions);
16037f1f268SConrad Meyer }
16137f1f268SConrad Meyer
162*5ff13fbcSAllan Jude /* set access and modification times */
UTIL_utime(const char * filename,const stat_t * statbuf)163*5ff13fbcSAllan Jude int UTIL_utime(const char* filename, const stat_t *statbuf)
164*5ff13fbcSAllan Jude {
165*5ff13fbcSAllan Jude int ret;
166*5ff13fbcSAllan Jude /* We check that st_mtime is a macro here in order to give us confidence
167*5ff13fbcSAllan Jude * that struct stat has a struct timespec st_mtim member. We need this
168*5ff13fbcSAllan Jude * check because there are some platforms that claim to be POSIX 2008
169*5ff13fbcSAllan Jude * compliant but which do not have st_mtim... */
170*5ff13fbcSAllan Jude #if (PLATFORM_POSIX_VERSION >= 200809L) && defined(st_mtime)
171*5ff13fbcSAllan Jude /* (atime, mtime) */
172*5ff13fbcSAllan Jude struct timespec timebuf[2] = { {0, UTIME_NOW} };
173*5ff13fbcSAllan Jude timebuf[1] = statbuf->st_mtim;
174*5ff13fbcSAllan Jude ret = utimensat(AT_FDCWD, filename, timebuf, 0);
175*5ff13fbcSAllan Jude #else
176*5ff13fbcSAllan Jude struct utimbuf timebuf;
177*5ff13fbcSAllan Jude timebuf.actime = time(NULL);
178*5ff13fbcSAllan Jude timebuf.modtime = statbuf->st_mtime;
179*5ff13fbcSAllan Jude ret = utime(filename, &timebuf);
180*5ff13fbcSAllan Jude #endif
181*5ff13fbcSAllan Jude errno = 0;
182*5ff13fbcSAllan Jude return ret;
183*5ff13fbcSAllan Jude }
184*5ff13fbcSAllan Jude
UTIL_setFileStat(const char * filename,const stat_t * statbuf)185f7cd7fe5SConrad Meyer int UTIL_setFileStat(const char *filename, const stat_t *statbuf)
186a0483764SConrad Meyer {
187a0483764SConrad Meyer int res = 0;
188a0483764SConrad Meyer
189f7cd7fe5SConrad Meyer stat_t curStatBuf;
190f7cd7fe5SConrad Meyer if (!UTIL_stat(filename, &curStatBuf) || !UTIL_isRegularFileStat(&curStatBuf))
191a0483764SConrad Meyer return -1;
192a0483764SConrad Meyer
1939cbefe25SConrad Meyer /* set access and modification times */
194*5ff13fbcSAllan Jude res += UTIL_utime(filename, statbuf);
195a0483764SConrad Meyer
196a0483764SConrad Meyer #if !defined(_WIN32)
197a0483764SConrad Meyer res += chown(filename, statbuf->st_uid, statbuf->st_gid); /* Copy ownership */
198a0483764SConrad Meyer #endif
199a0483764SConrad Meyer
200f7cd7fe5SConrad Meyer res += UTIL_chmod(filename, &curStatBuf, statbuf->st_mode & 07777); /* Copy file permissions */
201a0483764SConrad Meyer
202a0483764SConrad Meyer errno = 0;
203a0483764SConrad Meyer return -res; /* number of errors is returned */
204a0483764SConrad Meyer }
205a0483764SConrad Meyer
UTIL_isDirectory(const char * infilename)20637f1f268SConrad Meyer int UTIL_isDirectory(const char* infilename)
207a0483764SConrad Meyer {
208a0483764SConrad Meyer stat_t statbuf;
209f7cd7fe5SConrad Meyer return UTIL_stat(infilename, &statbuf) && UTIL_isDirectoryStat(&statbuf);
210f7cd7fe5SConrad Meyer }
211f7cd7fe5SConrad Meyer
UTIL_isDirectoryStat(const stat_t * statbuf)212f7cd7fe5SConrad Meyer int UTIL_isDirectoryStat(const stat_t* statbuf)
213f7cd7fe5SConrad Meyer {
214a0483764SConrad Meyer #if defined(_MSC_VER)
215f7cd7fe5SConrad Meyer return (statbuf->st_mode & _S_IFDIR) != 0;
216a0483764SConrad Meyer #else
217f7cd7fe5SConrad Meyer return S_ISDIR(statbuf->st_mode) != 0;
218a0483764SConrad Meyer #endif
219a0483764SConrad Meyer }
220a0483764SConrad Meyer
UTIL_compareStr(const void * p1,const void * p2)2219cbefe25SConrad Meyer int UTIL_compareStr(const void *p1, const void *p2) {
2229cbefe25SConrad Meyer return strcmp(* (char * const *) p1, * (char * const *) p2);
2239cbefe25SConrad Meyer }
2249cbefe25SConrad Meyer
UTIL_isSameFile(const char * fName1,const char * fName2)2259cbefe25SConrad Meyer int UTIL_isSameFile(const char* fName1, const char* fName2)
2262b9c00cbSConrad Meyer {
2279cbefe25SConrad Meyer assert(fName1 != NULL); assert(fName2 != NULL);
2289cbefe25SConrad Meyer #if defined(_MSC_VER) || defined(_WIN32)
2292b9c00cbSConrad Meyer /* note : Visual does not support file identification by inode.
2309cbefe25SConrad Meyer * inode does not work on Windows, even with a posix layer, like msys2.
2312b9c00cbSConrad Meyer * The following work-around is limited to detecting exact name repetition only,
2322b9c00cbSConrad Meyer * aka `filename` is considered different from `subdir/../filename` */
2339cbefe25SConrad Meyer return !strcmp(fName1, fName2);
2342b9c00cbSConrad Meyer #else
2359cbefe25SConrad Meyer { stat_t file1Stat;
2362b9c00cbSConrad Meyer stat_t file2Stat;
237f7cd7fe5SConrad Meyer return UTIL_stat(fName1, &file1Stat)
238f7cd7fe5SConrad Meyer && UTIL_stat(fName2, &file2Stat)
2392b9c00cbSConrad Meyer && (file1Stat.st_dev == file2Stat.st_dev)
2402b9c00cbSConrad Meyer && (file1Stat.st_ino == file2Stat.st_ino);
2419cbefe25SConrad Meyer }
2422b9c00cbSConrad Meyer #endif
2432b9c00cbSConrad Meyer }
2442b9c00cbSConrad Meyer
24537f1f268SConrad Meyer /* UTIL_isFIFO : distinguish named pipes */
UTIL_isFIFO(const char * infilename)24637f1f268SConrad Meyer int UTIL_isFIFO(const char* infilename)
2479cbefe25SConrad Meyer {
2489cbefe25SConrad Meyer /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
2499cbefe25SConrad Meyer #if PLATFORM_POSIX_VERSION >= 200112L
2509cbefe25SConrad Meyer stat_t statbuf;
251f7cd7fe5SConrad Meyer if (UTIL_stat(infilename, &statbuf) && UTIL_isFIFOStat(&statbuf)) return 1;
2529cbefe25SConrad Meyer #endif
2539cbefe25SConrad Meyer (void)infilename;
2549cbefe25SConrad Meyer return 0;
2559cbefe25SConrad Meyer }
2569cbefe25SConrad Meyer
257f7cd7fe5SConrad Meyer /* UTIL_isFIFO : distinguish named pipes */
UTIL_isFIFOStat(const stat_t * statbuf)258f7cd7fe5SConrad Meyer int UTIL_isFIFOStat(const stat_t* statbuf)
259f7cd7fe5SConrad Meyer {
260f7cd7fe5SConrad Meyer /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
261f7cd7fe5SConrad Meyer #if PLATFORM_POSIX_VERSION >= 200112L
262f7cd7fe5SConrad Meyer if (S_ISFIFO(statbuf->st_mode)) return 1;
263f7cd7fe5SConrad Meyer #endif
264f7cd7fe5SConrad Meyer (void)statbuf;
265f7cd7fe5SConrad Meyer return 0;
266f7cd7fe5SConrad Meyer }
267f7cd7fe5SConrad Meyer
268*5ff13fbcSAllan Jude /* UTIL_isBlockDevStat : distinguish named pipes */
UTIL_isBlockDevStat(const stat_t * statbuf)269*5ff13fbcSAllan Jude int UTIL_isBlockDevStat(const stat_t* statbuf)
270*5ff13fbcSAllan Jude {
271*5ff13fbcSAllan Jude /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
272*5ff13fbcSAllan Jude #if PLATFORM_POSIX_VERSION >= 200112L
273*5ff13fbcSAllan Jude if (S_ISBLK(statbuf->st_mode)) return 1;
274*5ff13fbcSAllan Jude #endif
275*5ff13fbcSAllan Jude (void)statbuf;
276*5ff13fbcSAllan Jude return 0;
277*5ff13fbcSAllan Jude }
278*5ff13fbcSAllan Jude
UTIL_isLink(const char * infilename)27937f1f268SConrad Meyer int UTIL_isLink(const char* infilename)
280a0483764SConrad Meyer {
281a0483764SConrad Meyer /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
2824d3f1eafSConrad Meyer #if PLATFORM_POSIX_VERSION >= 200112L
283a0483764SConrad Meyer stat_t statbuf;
28437f1f268SConrad Meyer int const r = lstat(infilename, &statbuf);
285a0483764SConrad Meyer if (!r && S_ISLNK(statbuf.st_mode)) return 1;
286a0483764SConrad Meyer #endif
287a0483764SConrad Meyer (void)infilename;
288a0483764SConrad Meyer return 0;
289a0483764SConrad Meyer }
290a0483764SConrad Meyer
UTIL_getFileSize(const char * infilename)291a0483764SConrad Meyer U64 UTIL_getFileSize(const char* infilename)
292a0483764SConrad Meyer {
293f7cd7fe5SConrad Meyer stat_t statbuf;
294f7cd7fe5SConrad Meyer if (!UTIL_stat(infilename, &statbuf)) return UTIL_FILESIZE_UNKNOWN;
295f7cd7fe5SConrad Meyer return UTIL_getFileSizeStat(&statbuf);
296a0483764SConrad Meyer }
297f7cd7fe5SConrad Meyer
UTIL_getFileSizeStat(const stat_t * statbuf)298f7cd7fe5SConrad Meyer U64 UTIL_getFileSizeStat(const stat_t* statbuf)
299f7cd7fe5SConrad Meyer {
300f7cd7fe5SConrad Meyer if (!UTIL_isRegularFileStat(statbuf)) return UTIL_FILESIZE_UNKNOWN;
301f7cd7fe5SConrad Meyer #if defined(_MSC_VER)
302f7cd7fe5SConrad Meyer if (!(statbuf->st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
303f7cd7fe5SConrad Meyer #elif defined(__MINGW32__) && defined (__MSVCRT__)
304f7cd7fe5SConrad Meyer if (!(statbuf->st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
305f7cd7fe5SConrad Meyer #else
306f7cd7fe5SConrad Meyer if (!S_ISREG(statbuf->st_mode)) return UTIL_FILESIZE_UNKNOWN;
307f7cd7fe5SConrad Meyer #endif
308f7cd7fe5SConrad Meyer return (U64)statbuf->st_size;
309a0483764SConrad Meyer }
310a0483764SConrad Meyer
UTIL_makeHumanReadableSize(U64 size)311*5ff13fbcSAllan Jude UTIL_HumanReadableSize_t UTIL_makeHumanReadableSize(U64 size)
312*5ff13fbcSAllan Jude {
313*5ff13fbcSAllan Jude UTIL_HumanReadableSize_t hrs;
314*5ff13fbcSAllan Jude
315*5ff13fbcSAllan Jude if (g_utilDisplayLevel > 3) {
316*5ff13fbcSAllan Jude /* In verbose mode, do not scale sizes down, except in the case of
317*5ff13fbcSAllan Jude * values that exceed the integral precision of a double. */
318*5ff13fbcSAllan Jude if (size >= (1ull << 53)) {
319*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 20);
320*5ff13fbcSAllan Jude hrs.suffix = " MiB";
321*5ff13fbcSAllan Jude /* At worst, a double representation of a maximal size will be
322*5ff13fbcSAllan Jude * accurate to better than tens of kilobytes. */
323*5ff13fbcSAllan Jude hrs.precision = 2;
324*5ff13fbcSAllan Jude } else {
325*5ff13fbcSAllan Jude hrs.value = (double)size;
326*5ff13fbcSAllan Jude hrs.suffix = " B";
327*5ff13fbcSAllan Jude hrs.precision = 0;
328*5ff13fbcSAllan Jude }
329*5ff13fbcSAllan Jude } else {
330*5ff13fbcSAllan Jude /* In regular mode, scale sizes down and use suffixes. */
331*5ff13fbcSAllan Jude if (size >= (1ull << 60)) {
332*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 60);
333*5ff13fbcSAllan Jude hrs.suffix = " EiB";
334*5ff13fbcSAllan Jude } else if (size >= (1ull << 50)) {
335*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 50);
336*5ff13fbcSAllan Jude hrs.suffix = " PiB";
337*5ff13fbcSAllan Jude } else if (size >= (1ull << 40)) {
338*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 40);
339*5ff13fbcSAllan Jude hrs.suffix = " TiB";
340*5ff13fbcSAllan Jude } else if (size >= (1ull << 30)) {
341*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 30);
342*5ff13fbcSAllan Jude hrs.suffix = " GiB";
343*5ff13fbcSAllan Jude } else if (size >= (1ull << 20)) {
344*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 20);
345*5ff13fbcSAllan Jude hrs.suffix = " MiB";
346*5ff13fbcSAllan Jude } else if (size >= (1ull << 10)) {
347*5ff13fbcSAllan Jude hrs.value = (double)size / (1ull << 10);
348*5ff13fbcSAllan Jude hrs.suffix = " KiB";
349*5ff13fbcSAllan Jude } else {
350*5ff13fbcSAllan Jude hrs.value = (double)size;
351*5ff13fbcSAllan Jude hrs.suffix = " B";
352*5ff13fbcSAllan Jude }
353*5ff13fbcSAllan Jude
354*5ff13fbcSAllan Jude if (hrs.value >= 100 || (U64)hrs.value == size) {
355*5ff13fbcSAllan Jude hrs.precision = 0;
356*5ff13fbcSAllan Jude } else if (hrs.value >= 10) {
357*5ff13fbcSAllan Jude hrs.precision = 1;
358*5ff13fbcSAllan Jude } else if (hrs.value > 1) {
359*5ff13fbcSAllan Jude hrs.precision = 2;
360*5ff13fbcSAllan Jude } else {
361*5ff13fbcSAllan Jude hrs.precision = 3;
362*5ff13fbcSAllan Jude }
363*5ff13fbcSAllan Jude }
364*5ff13fbcSAllan Jude
365*5ff13fbcSAllan Jude return hrs;
366*5ff13fbcSAllan Jude }
367a0483764SConrad Meyer
UTIL_getTotalFileSize(const char * const * fileNamesTable,unsigned nbFiles)36837f1f268SConrad Meyer U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles)
369a0483764SConrad Meyer {
370a0483764SConrad Meyer U64 total = 0;
371a0483764SConrad Meyer unsigned n;
372a0483764SConrad Meyer for (n=0; n<nbFiles; n++) {
373a0483764SConrad Meyer U64 const size = UTIL_getFileSize(fileNamesTable[n]);
37437f1f268SConrad Meyer if (size == UTIL_FILESIZE_UNKNOWN) return UTIL_FILESIZE_UNKNOWN;
375a0483764SConrad Meyer total += size;
376a0483764SConrad Meyer }
37737f1f268SConrad Meyer return total;
37837f1f268SConrad Meyer }
37937f1f268SConrad Meyer
38037f1f268SConrad Meyer
38137f1f268SConrad Meyer /* condition : @file must be valid, and not have reached its end.
38237f1f268SConrad Meyer * @return : length of line written into @buf, ended with `\0` instead of '\n',
38337f1f268SConrad Meyer * or 0, if there is no new line */
readLineFromFile(char * buf,size_t len,FILE * file)38437f1f268SConrad Meyer static size_t readLineFromFile(char* buf, size_t len, FILE* file)
38537f1f268SConrad Meyer {
38637f1f268SConrad Meyer assert(!feof(file));
387*5ff13fbcSAllan Jude if ( fgets(buf, (int) len, file) == NULL ) return 0;
38837f1f268SConrad Meyer { size_t linelen = strlen(buf);
38937f1f268SConrad Meyer if (strlen(buf)==0) return 0;
39037f1f268SConrad Meyer if (buf[linelen-1] == '\n') linelen--;
39137f1f268SConrad Meyer buf[linelen] = '\0';
39237f1f268SConrad Meyer return linelen+1;
39337f1f268SConrad Meyer }
39437f1f268SConrad Meyer }
39537f1f268SConrad Meyer
39637f1f268SConrad Meyer /* Conditions :
39737f1f268SConrad Meyer * size of @inputFileName file must be < @dstCapacity
39837f1f268SConrad Meyer * @dst must be initialized
39937f1f268SConrad Meyer * @return : nb of lines
40037f1f268SConrad Meyer * or -1 if there's an error
40137f1f268SConrad Meyer */
40237f1f268SConrad Meyer static int
readLinesFromFile(void * dst,size_t dstCapacity,const char * inputFileName)40337f1f268SConrad Meyer readLinesFromFile(void* dst, size_t dstCapacity,
40437f1f268SConrad Meyer const char* inputFileName)
40537f1f268SConrad Meyer {
40637f1f268SConrad Meyer int nbFiles = 0;
40737f1f268SConrad Meyer size_t pos = 0;
40837f1f268SConrad Meyer char* const buf = (char*)dst;
40937f1f268SConrad Meyer FILE* const inputFile = fopen(inputFileName, "r");
41037f1f268SConrad Meyer
41137f1f268SConrad Meyer assert(dst != NULL);
41237f1f268SConrad Meyer
41337f1f268SConrad Meyer if(!inputFile) {
41437f1f268SConrad Meyer if (g_utilDisplayLevel >= 1) perror("zstd:util:readLinesFromFile");
41537f1f268SConrad Meyer return -1;
41637f1f268SConrad Meyer }
41737f1f268SConrad Meyer
41837f1f268SConrad Meyer while ( !feof(inputFile) ) {
41937f1f268SConrad Meyer size_t const lineLength = readLineFromFile(buf+pos, dstCapacity-pos, inputFile);
42037f1f268SConrad Meyer if (lineLength == 0) break;
42137f1f268SConrad Meyer assert(pos + lineLength < dstCapacity);
42237f1f268SConrad Meyer pos += lineLength;
42337f1f268SConrad Meyer ++nbFiles;
42437f1f268SConrad Meyer }
42537f1f268SConrad Meyer
42637f1f268SConrad Meyer CONTROL( fclose(inputFile) == 0 );
42737f1f268SConrad Meyer
42837f1f268SConrad Meyer return nbFiles;
42937f1f268SConrad Meyer }
43037f1f268SConrad Meyer
43137f1f268SConrad Meyer /*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/
43237f1f268SConrad Meyer FileNamesTable*
UTIL_createFileNamesTable_fromFileName(const char * inputFileName)43337f1f268SConrad Meyer UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
43437f1f268SConrad Meyer {
43537f1f268SConrad Meyer size_t nbFiles = 0;
43637f1f268SConrad Meyer char* buf;
43737f1f268SConrad Meyer size_t bufSize;
43837f1f268SConrad Meyer size_t pos = 0;
439f7cd7fe5SConrad Meyer stat_t statbuf;
44037f1f268SConrad Meyer
441f7cd7fe5SConrad Meyer if (!UTIL_stat(inputFileName, &statbuf) || !UTIL_isRegularFileStat(&statbuf))
44237f1f268SConrad Meyer return NULL;
44337f1f268SConrad Meyer
444f7cd7fe5SConrad Meyer { U64 const inputFileSize = UTIL_getFileSizeStat(&statbuf);
44537f1f268SConrad Meyer if(inputFileSize > MAX_FILE_OF_FILE_NAMES_SIZE)
44637f1f268SConrad Meyer return NULL;
44737f1f268SConrad Meyer bufSize = (size_t)(inputFileSize + 1); /* (+1) to add '\0' at the end of last filename */
44837f1f268SConrad Meyer }
44937f1f268SConrad Meyer
45037f1f268SConrad Meyer buf = (char*) malloc(bufSize);
45137f1f268SConrad Meyer CONTROL( buf != NULL );
45237f1f268SConrad Meyer
45337f1f268SConrad Meyer { int const ret_nbFiles = readLinesFromFile(buf, bufSize, inputFileName);
45437f1f268SConrad Meyer
45537f1f268SConrad Meyer if (ret_nbFiles <= 0) {
45637f1f268SConrad Meyer free(buf);
45737f1f268SConrad Meyer return NULL;
45837f1f268SConrad Meyer }
45937f1f268SConrad Meyer nbFiles = (size_t)ret_nbFiles;
46037f1f268SConrad Meyer }
46137f1f268SConrad Meyer
46237f1f268SConrad Meyer { const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable));
46337f1f268SConrad Meyer CONTROL(filenamesTable != NULL);
46437f1f268SConrad Meyer
46537f1f268SConrad Meyer { size_t fnb;
46637f1f268SConrad Meyer for (fnb = 0, pos = 0; fnb < nbFiles; fnb++) {
46737f1f268SConrad Meyer filenamesTable[fnb] = buf+pos;
46837f1f268SConrad Meyer pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */
46937f1f268SConrad Meyer } }
47037f1f268SConrad Meyer assert(pos <= bufSize);
47137f1f268SConrad Meyer
47237f1f268SConrad Meyer return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf);
47337f1f268SConrad Meyer }
47437f1f268SConrad Meyer }
47537f1f268SConrad Meyer
47637f1f268SConrad Meyer static FileNamesTable*
UTIL_assembleFileNamesTable2(const char ** filenames,size_t tableSize,size_t tableCapacity,char * buf)47737f1f268SConrad Meyer UTIL_assembleFileNamesTable2(const char** filenames, size_t tableSize, size_t tableCapacity, char* buf)
47837f1f268SConrad Meyer {
47937f1f268SConrad Meyer FileNamesTable* const table = (FileNamesTable*) malloc(sizeof(*table));
48037f1f268SConrad Meyer CONTROL(table != NULL);
48137f1f268SConrad Meyer table->fileNames = filenames;
48237f1f268SConrad Meyer table->buf = buf;
48337f1f268SConrad Meyer table->tableSize = tableSize;
48437f1f268SConrad Meyer table->tableCapacity = tableCapacity;
48537f1f268SConrad Meyer return table;
48637f1f268SConrad Meyer }
48737f1f268SConrad Meyer
48837f1f268SConrad Meyer FileNamesTable*
UTIL_assembleFileNamesTable(const char ** filenames,size_t tableSize,char * buf)48937f1f268SConrad Meyer UTIL_assembleFileNamesTable(const char** filenames, size_t tableSize, char* buf)
49037f1f268SConrad Meyer {
49137f1f268SConrad Meyer return UTIL_assembleFileNamesTable2(filenames, tableSize, tableSize, buf);
49237f1f268SConrad Meyer }
49337f1f268SConrad Meyer
UTIL_freeFileNamesTable(FileNamesTable * table)49437f1f268SConrad Meyer void UTIL_freeFileNamesTable(FileNamesTable* table)
49537f1f268SConrad Meyer {
49637f1f268SConrad Meyer if (table==NULL) return;
49737f1f268SConrad Meyer free((void*)table->fileNames);
49837f1f268SConrad Meyer free(table->buf);
49937f1f268SConrad Meyer free(table);
50037f1f268SConrad Meyer }
50137f1f268SConrad Meyer
UTIL_allocateFileNamesTable(size_t tableSize)50237f1f268SConrad Meyer FileNamesTable* UTIL_allocateFileNamesTable(size_t tableSize)
50337f1f268SConrad Meyer {
50437f1f268SConrad Meyer const char** const fnTable = (const char**)malloc(tableSize * sizeof(*fnTable));
50537f1f268SConrad Meyer FileNamesTable* fnt;
50637f1f268SConrad Meyer if (fnTable==NULL) return NULL;
50737f1f268SConrad Meyer fnt = UTIL_assembleFileNamesTable(fnTable, tableSize, NULL);
50837f1f268SConrad Meyer fnt->tableSize = 0; /* the table is empty */
50937f1f268SConrad Meyer return fnt;
51037f1f268SConrad Meyer }
51137f1f268SConrad Meyer
UTIL_refFilename(FileNamesTable * fnt,const char * filename)51237f1f268SConrad Meyer void UTIL_refFilename(FileNamesTable* fnt, const char* filename)
51337f1f268SConrad Meyer {
51437f1f268SConrad Meyer assert(fnt->tableSize < fnt->tableCapacity);
51537f1f268SConrad Meyer fnt->fileNames[fnt->tableSize] = filename;
51637f1f268SConrad Meyer fnt->tableSize++;
51737f1f268SConrad Meyer }
51837f1f268SConrad Meyer
getTotalTableSize(FileNamesTable * table)51937f1f268SConrad Meyer static size_t getTotalTableSize(FileNamesTable* table)
52037f1f268SConrad Meyer {
52137f1f268SConrad Meyer size_t fnb = 0, totalSize = 0;
52237f1f268SConrad Meyer for(fnb = 0 ; fnb < table->tableSize && table->fileNames[fnb] ; ++fnb) {
52337f1f268SConrad Meyer totalSize += strlen(table->fileNames[fnb]) + 1; /* +1 to add '\0' at the end of each fileName */
52437f1f268SConrad Meyer }
52537f1f268SConrad Meyer return totalSize;
52637f1f268SConrad Meyer }
52737f1f268SConrad Meyer
52837f1f268SConrad Meyer FileNamesTable*
UTIL_mergeFileNamesTable(FileNamesTable * table1,FileNamesTable * table2)52937f1f268SConrad Meyer UTIL_mergeFileNamesTable(FileNamesTable* table1, FileNamesTable* table2)
53037f1f268SConrad Meyer {
53137f1f268SConrad Meyer unsigned newTableIdx = 0;
53237f1f268SConrad Meyer size_t pos = 0;
53337f1f268SConrad Meyer size_t newTotalTableSize;
53437f1f268SConrad Meyer char* buf;
53537f1f268SConrad Meyer
53637f1f268SConrad Meyer FileNamesTable* const newTable = UTIL_assembleFileNamesTable(NULL, 0, NULL);
53737f1f268SConrad Meyer CONTROL( newTable != NULL );
53837f1f268SConrad Meyer
53937f1f268SConrad Meyer newTotalTableSize = getTotalTableSize(table1) + getTotalTableSize(table2);
54037f1f268SConrad Meyer
54137f1f268SConrad Meyer buf = (char*) calloc(newTotalTableSize, sizeof(*buf));
54237f1f268SConrad Meyer CONTROL ( buf != NULL );
54337f1f268SConrad Meyer
54437f1f268SConrad Meyer newTable->buf = buf;
54537f1f268SConrad Meyer newTable->tableSize = table1->tableSize + table2->tableSize;
54637f1f268SConrad Meyer newTable->fileNames = (const char **) calloc(newTable->tableSize, sizeof(*(newTable->fileNames)));
54737f1f268SConrad Meyer CONTROL ( newTable->fileNames != NULL );
54837f1f268SConrad Meyer
54937f1f268SConrad Meyer { unsigned idx1;
55037f1f268SConrad Meyer for( idx1=0 ; (idx1 < table1->tableSize) && table1->fileNames[idx1] && (pos < newTotalTableSize); ++idx1, ++newTableIdx) {
55137f1f268SConrad Meyer size_t const curLen = strlen(table1->fileNames[idx1]);
55237f1f268SConrad Meyer memcpy(buf+pos, table1->fileNames[idx1], curLen);
55337f1f268SConrad Meyer assert(newTableIdx <= newTable->tableSize);
55437f1f268SConrad Meyer newTable->fileNames[newTableIdx] = buf+pos;
55537f1f268SConrad Meyer pos += curLen+1;
55637f1f268SConrad Meyer } }
55737f1f268SConrad Meyer
55837f1f268SConrad Meyer { unsigned idx2;
55937f1f268SConrad Meyer for( idx2=0 ; (idx2 < table2->tableSize) && table2->fileNames[idx2] && (pos < newTotalTableSize) ; ++idx2, ++newTableIdx) {
56037f1f268SConrad Meyer size_t const curLen = strlen(table2->fileNames[idx2]);
56137f1f268SConrad Meyer memcpy(buf+pos, table2->fileNames[idx2], curLen);
56237f1f268SConrad Meyer assert(newTableIdx <= newTable->tableSize);
56337f1f268SConrad Meyer newTable->fileNames[newTableIdx] = buf+pos;
56437f1f268SConrad Meyer pos += curLen+1;
56537f1f268SConrad Meyer } }
56637f1f268SConrad Meyer assert(pos <= newTotalTableSize);
56737f1f268SConrad Meyer newTable->tableSize = newTableIdx;
56837f1f268SConrad Meyer
56937f1f268SConrad Meyer UTIL_freeFileNamesTable(table1);
57037f1f268SConrad Meyer UTIL_freeFileNamesTable(table2);
57137f1f268SConrad Meyer
57237f1f268SConrad Meyer return newTable;
573a0483764SConrad Meyer }
574a0483764SConrad Meyer
575a0483764SConrad Meyer #ifdef _WIN32
UTIL_prepareFileList(const char * dirName,char ** bufStart,size_t * pos,char ** bufEnd,int followLinks)57637f1f268SConrad Meyer static int UTIL_prepareFileList(const char* dirName,
57737f1f268SConrad Meyer char** bufStart, size_t* pos,
57837f1f268SConrad Meyer char** bufEnd, int followLinks)
579a0483764SConrad Meyer {
580a0483764SConrad Meyer char* path;
58137f1f268SConrad Meyer size_t dirLength, pathLength;
58237f1f268SConrad Meyer int nbFiles = 0;
583a0483764SConrad Meyer WIN32_FIND_DATAA cFile;
584a0483764SConrad Meyer HANDLE hFile;
585a0483764SConrad Meyer
58637f1f268SConrad Meyer dirLength = strlen(dirName);
587a0483764SConrad Meyer path = (char*) malloc(dirLength + 3);
588a0483764SConrad Meyer if (!path) return 0;
589a0483764SConrad Meyer
590a0483764SConrad Meyer memcpy(path, dirName, dirLength);
591a0483764SConrad Meyer path[dirLength] = '\\';
592a0483764SConrad Meyer path[dirLength+1] = '*';
593a0483764SConrad Meyer path[dirLength+2] = 0;
594a0483764SConrad Meyer
595a0483764SConrad Meyer hFile=FindFirstFileA(path, &cFile);
596a0483764SConrad Meyer if (hFile == INVALID_HANDLE_VALUE) {
597a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName);
598a0483764SConrad Meyer return 0;
599a0483764SConrad Meyer }
600a0483764SConrad Meyer free(path);
601a0483764SConrad Meyer
602a0483764SConrad Meyer do {
60337f1f268SConrad Meyer size_t const fnameLength = strlen(cFile.cFileName);
604a0483764SConrad Meyer path = (char*) malloc(dirLength + fnameLength + 2);
605a0483764SConrad Meyer if (!path) { FindClose(hFile); return 0; }
606a0483764SConrad Meyer memcpy(path, dirName, dirLength);
607a0483764SConrad Meyer path[dirLength] = '\\';
608a0483764SConrad Meyer memcpy(path+dirLength+1, cFile.cFileName, fnameLength);
609a0483764SConrad Meyer pathLength = dirLength+1+fnameLength;
610a0483764SConrad Meyer path[pathLength] = 0;
611a0483764SConrad Meyer if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
612a0483764SConrad Meyer if ( strcmp (cFile.cFileName, "..") == 0
613a0483764SConrad Meyer || strcmp (cFile.cFileName, ".") == 0 )
614a0483764SConrad Meyer continue;
615a0483764SConrad Meyer /* Recursively call "UTIL_prepareFileList" with the new path. */
616a0483764SConrad Meyer nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks);
617a0483764SConrad Meyer if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
618a0483764SConrad Meyer } else if ( (cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
619a0483764SConrad Meyer || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
620a0483764SConrad Meyer || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) {
621a0483764SConrad Meyer if (*bufStart + *pos + pathLength >= *bufEnd) {
622a0483764SConrad Meyer ptrdiff_t const newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
623a0483764SConrad Meyer *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
624a0483764SConrad Meyer if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
625a0483764SConrad Meyer *bufEnd = *bufStart + newListSize;
626a0483764SConrad Meyer }
627a0483764SConrad Meyer if (*bufStart + *pos + pathLength < *bufEnd) {
628a0483764SConrad Meyer memcpy(*bufStart + *pos, path, pathLength+1 /* include final \0 */);
629a0483764SConrad Meyer *pos += pathLength + 1;
630a0483764SConrad Meyer nbFiles++;
63137f1f268SConrad Meyer } }
632a0483764SConrad Meyer free(path);
633a0483764SConrad Meyer } while (FindNextFileA(hFile, &cFile));
634a0483764SConrad Meyer
635a0483764SConrad Meyer FindClose(hFile);
636a0483764SConrad Meyer return nbFiles;
637a0483764SConrad Meyer }
638a0483764SConrad Meyer
639a0483764SConrad Meyer #elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */
640a0483764SConrad Meyer
UTIL_prepareFileList(const char * dirName,char ** bufStart,size_t * pos,char ** bufEnd,int followLinks)64137f1f268SConrad Meyer static int UTIL_prepareFileList(const char *dirName,
64237f1f268SConrad Meyer char** bufStart, size_t* pos,
64337f1f268SConrad Meyer char** bufEnd, int followLinks)
644a0483764SConrad Meyer {
645a0483764SConrad Meyer DIR* dir;
646a0483764SConrad Meyer struct dirent * entry;
64737f1f268SConrad Meyer size_t dirLength;
6489cbefe25SConrad Meyer int nbFiles = 0;
649a0483764SConrad Meyer
650a0483764SConrad Meyer if (!(dir = opendir(dirName))) {
651a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
652a0483764SConrad Meyer return 0;
653a0483764SConrad Meyer }
654a0483764SConrad Meyer
6559cbefe25SConrad Meyer dirLength = strlen(dirName);
656a0483764SConrad Meyer errno = 0;
657a0483764SConrad Meyer while ((entry = readdir(dir)) != NULL) {
65837f1f268SConrad Meyer char* path;
65937f1f268SConrad Meyer size_t fnameLength, pathLength;
660a0483764SConrad Meyer if (strcmp (entry->d_name, "..") == 0 ||
661a0483764SConrad Meyer strcmp (entry->d_name, ".") == 0) continue;
6629cbefe25SConrad Meyer fnameLength = strlen(entry->d_name);
663a0483764SConrad Meyer path = (char*) malloc(dirLength + fnameLength + 2);
664a0483764SConrad Meyer if (!path) { closedir(dir); return 0; }
665a0483764SConrad Meyer memcpy(path, dirName, dirLength);
666a0483764SConrad Meyer
667a0483764SConrad Meyer path[dirLength] = '/';
668a0483764SConrad Meyer memcpy(path+dirLength+1, entry->d_name, fnameLength);
669a0483764SConrad Meyer pathLength = dirLength+1+fnameLength;
670a0483764SConrad Meyer path[pathLength] = 0;
671a0483764SConrad Meyer
672a0483764SConrad Meyer if (!followLinks && UTIL_isLink(path)) {
673a0483764SConrad Meyer UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path);
6744d3f1eafSConrad Meyer free(path);
675a0483764SConrad Meyer continue;
676a0483764SConrad Meyer }
677a0483764SConrad Meyer
678a0483764SConrad Meyer if (UTIL_isDirectory(path)) {
679a0483764SConrad Meyer nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */
680a0483764SConrad Meyer if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
681a0483764SConrad Meyer } else {
682a0483764SConrad Meyer if (*bufStart + *pos + pathLength >= *bufEnd) {
683a0483764SConrad Meyer ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
6849cbefe25SConrad Meyer assert(newListSize >= 0);
6859cbefe25SConrad Meyer *bufStart = (char*)UTIL_realloc(*bufStart, (size_t)newListSize);
686a0483764SConrad Meyer *bufEnd = *bufStart + newListSize;
687a0483764SConrad Meyer if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
688a0483764SConrad Meyer }
689a0483764SConrad Meyer if (*bufStart + *pos + pathLength < *bufEnd) {
690a0483764SConrad Meyer memcpy(*bufStart + *pos, path, pathLength + 1); /* with final \0 */
691a0483764SConrad Meyer *pos += pathLength + 1;
692a0483764SConrad Meyer nbFiles++;
69337f1f268SConrad Meyer } }
694a0483764SConrad Meyer free(path);
695a0483764SConrad Meyer errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */
696a0483764SConrad Meyer }
697a0483764SConrad Meyer
698a0483764SConrad Meyer if (errno != 0) {
699a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s \n", dirName, strerror(errno));
700a0483764SConrad Meyer free(*bufStart);
701a0483764SConrad Meyer *bufStart = NULL;
702a0483764SConrad Meyer }
703a0483764SConrad Meyer closedir(dir);
704a0483764SConrad Meyer return nbFiles;
705a0483764SConrad Meyer }
706a0483764SConrad Meyer
707a0483764SConrad Meyer #else
708a0483764SConrad Meyer
UTIL_prepareFileList(const char * dirName,char ** bufStart,size_t * pos,char ** bufEnd,int followLinks)70937f1f268SConrad Meyer static int UTIL_prepareFileList(const char *dirName,
71037f1f268SConrad Meyer char** bufStart, size_t* pos,
71137f1f268SConrad Meyer char** bufEnd, int followLinks)
712a0483764SConrad Meyer {
713a0483764SConrad Meyer (void)bufStart; (void)bufEnd; (void)pos; (void)followLinks;
714a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE) \n", dirName);
715a0483764SConrad Meyer return 0;
716a0483764SConrad Meyer }
717a0483764SConrad Meyer
718a0483764SConrad Meyer #endif /* #ifdef _WIN32 */
719a0483764SConrad Meyer
UTIL_isCompressedFile(const char * inputName,const char * extensionList[])7209cbefe25SConrad Meyer int UTIL_isCompressedFile(const char *inputName, const char *extensionList[])
7219cbefe25SConrad Meyer {
7229cbefe25SConrad Meyer const char* ext = UTIL_getFileExtension(inputName);
7239cbefe25SConrad Meyer while(*extensionList!=NULL)
7249cbefe25SConrad Meyer {
7259cbefe25SConrad Meyer const int isCompressedExtension = strcmp(ext,*extensionList);
7269cbefe25SConrad Meyer if(isCompressedExtension==0)
7279cbefe25SConrad Meyer return 1;
7289cbefe25SConrad Meyer ++extensionList;
7299cbefe25SConrad Meyer }
7309cbefe25SConrad Meyer return 0;
7319cbefe25SConrad Meyer }
7329cbefe25SConrad Meyer
7339cbefe25SConrad Meyer /*Utility function to get file extension from file */
UTIL_getFileExtension(const char * infilename)7349cbefe25SConrad Meyer const char* UTIL_getFileExtension(const char* infilename)
7359cbefe25SConrad Meyer {
7369cbefe25SConrad Meyer const char* extension = strrchr(infilename, '.');
7379cbefe25SConrad Meyer if(!extension || extension==infilename) return "";
7389cbefe25SConrad Meyer return extension;
7399cbefe25SConrad Meyer }
7409cbefe25SConrad Meyer
pathnameHas2Dots(const char * pathname)741f7cd7fe5SConrad Meyer static int pathnameHas2Dots(const char *pathname)
742f7cd7fe5SConrad Meyer {
743*5ff13fbcSAllan Jude /* We need to figure out whether any ".." present in the path is a whole
744*5ff13fbcSAllan Jude * path token, which is the case if it is bordered on both sides by either
745*5ff13fbcSAllan Jude * the beginning/end of the path or by a directory separator.
746*5ff13fbcSAllan Jude */
747*5ff13fbcSAllan Jude const char *needle = pathname;
748*5ff13fbcSAllan Jude while (1) {
749*5ff13fbcSAllan Jude needle = strstr(needle, "..");
750*5ff13fbcSAllan Jude
751*5ff13fbcSAllan Jude if (needle == NULL) {
752*5ff13fbcSAllan Jude return 0;
753*5ff13fbcSAllan Jude }
754*5ff13fbcSAllan Jude
755*5ff13fbcSAllan Jude if ((needle == pathname || needle[-1] == PATH_SEP)
756*5ff13fbcSAllan Jude && (needle[2] == '\0' || needle[2] == PATH_SEP)) {
757*5ff13fbcSAllan Jude return 1;
758*5ff13fbcSAllan Jude }
759*5ff13fbcSAllan Jude
760*5ff13fbcSAllan Jude /* increment so we search for the next match */
761*5ff13fbcSAllan Jude needle++;
762*5ff13fbcSAllan Jude };
763*5ff13fbcSAllan Jude return 0;
764f7cd7fe5SConrad Meyer }
765f7cd7fe5SConrad Meyer
isFileNameValidForMirroredOutput(const char * filename)766f7cd7fe5SConrad Meyer static int isFileNameValidForMirroredOutput(const char *filename)
767f7cd7fe5SConrad Meyer {
768f7cd7fe5SConrad Meyer return !pathnameHas2Dots(filename);
769f7cd7fe5SConrad Meyer }
770f7cd7fe5SConrad Meyer
771f7cd7fe5SConrad Meyer
772f7cd7fe5SConrad Meyer #define DIR_DEFAULT_MODE 0755
getDirMode(const char * dirName)773f7cd7fe5SConrad Meyer static mode_t getDirMode(const char *dirName)
774f7cd7fe5SConrad Meyer {
775f7cd7fe5SConrad Meyer stat_t st;
776f7cd7fe5SConrad Meyer if (!UTIL_stat(dirName, &st)) {
777f7cd7fe5SConrad Meyer UTIL_DISPLAY("zstd: failed to get DIR stats %s: %s\n", dirName, strerror(errno));
778f7cd7fe5SConrad Meyer return DIR_DEFAULT_MODE;
779f7cd7fe5SConrad Meyer }
780f7cd7fe5SConrad Meyer if (!UTIL_isDirectoryStat(&st)) {
781f7cd7fe5SConrad Meyer UTIL_DISPLAY("zstd: expected directory: %s\n", dirName);
782f7cd7fe5SConrad Meyer return DIR_DEFAULT_MODE;
783f7cd7fe5SConrad Meyer }
784f7cd7fe5SConrad Meyer return st.st_mode;
785f7cd7fe5SConrad Meyer }
786f7cd7fe5SConrad Meyer
makeDir(const char * dir,mode_t mode)787f7cd7fe5SConrad Meyer static int makeDir(const char *dir, mode_t mode)
788f7cd7fe5SConrad Meyer {
789f7cd7fe5SConrad Meyer #if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
790f7cd7fe5SConrad Meyer int ret = _mkdir(dir);
791f7cd7fe5SConrad Meyer (void) mode;
792f7cd7fe5SConrad Meyer #else
793f7cd7fe5SConrad Meyer int ret = mkdir(dir, mode);
794f7cd7fe5SConrad Meyer #endif
795f7cd7fe5SConrad Meyer if (ret != 0) {
796f7cd7fe5SConrad Meyer if (errno == EEXIST)
797f7cd7fe5SConrad Meyer return 0;
798f7cd7fe5SConrad Meyer UTIL_DISPLAY("zstd: failed to create DIR %s: %s\n", dir, strerror(errno));
799f7cd7fe5SConrad Meyer }
800f7cd7fe5SConrad Meyer return ret;
801f7cd7fe5SConrad Meyer }
802f7cd7fe5SConrad Meyer
803f7cd7fe5SConrad Meyer /* this function requires a mutable input string */
convertPathnameToDirName(char * pathname)804f7cd7fe5SConrad Meyer static void convertPathnameToDirName(char *pathname)
805f7cd7fe5SConrad Meyer {
806f7cd7fe5SConrad Meyer size_t len = 0;
807f7cd7fe5SConrad Meyer char* pos = NULL;
808f7cd7fe5SConrad Meyer /* get dir name from pathname similar to 'dirname()' */
809f7cd7fe5SConrad Meyer assert(pathname != NULL);
810f7cd7fe5SConrad Meyer
811f7cd7fe5SConrad Meyer /* remove trailing '/' chars */
812f7cd7fe5SConrad Meyer len = strlen(pathname);
813f7cd7fe5SConrad Meyer assert(len > 0);
814f7cd7fe5SConrad Meyer while (pathname[len] == PATH_SEP) {
815f7cd7fe5SConrad Meyer pathname[len] = '\0';
816f7cd7fe5SConrad Meyer len--;
817f7cd7fe5SConrad Meyer }
818f7cd7fe5SConrad Meyer if (len == 0) return;
819f7cd7fe5SConrad Meyer
820f7cd7fe5SConrad Meyer /* if input is a single file, return '.' instead. i.e.
821f7cd7fe5SConrad Meyer * "xyz/abc/file.txt" => "xyz/abc"
822f7cd7fe5SConrad Meyer "./file.txt" => "."
823f7cd7fe5SConrad Meyer "file.txt" => "."
824f7cd7fe5SConrad Meyer */
825f7cd7fe5SConrad Meyer pos = strrchr(pathname, PATH_SEP);
826f7cd7fe5SConrad Meyer if (pos == NULL) {
827f7cd7fe5SConrad Meyer pathname[0] = '.';
828f7cd7fe5SConrad Meyer pathname[1] = '\0';
829f7cd7fe5SConrad Meyer } else {
830f7cd7fe5SConrad Meyer *pos = '\0';
831f7cd7fe5SConrad Meyer }
832f7cd7fe5SConrad Meyer }
833f7cd7fe5SConrad Meyer
834f7cd7fe5SConrad Meyer /* pathname must be valid */
trimLeadingRootChar(const char * pathname)835f7cd7fe5SConrad Meyer static const char* trimLeadingRootChar(const char *pathname)
836f7cd7fe5SConrad Meyer {
837f7cd7fe5SConrad Meyer assert(pathname != NULL);
838f7cd7fe5SConrad Meyer if (pathname[0] == PATH_SEP)
839f7cd7fe5SConrad Meyer return pathname + 1;
840f7cd7fe5SConrad Meyer return pathname;
841f7cd7fe5SConrad Meyer }
842f7cd7fe5SConrad Meyer
843f7cd7fe5SConrad Meyer /* pathname must be valid */
trimLeadingCurrentDirConst(const char * pathname)844f7cd7fe5SConrad Meyer static const char* trimLeadingCurrentDirConst(const char *pathname)
845f7cd7fe5SConrad Meyer {
846f7cd7fe5SConrad Meyer assert(pathname != NULL);
847f7cd7fe5SConrad Meyer if ((pathname[0] == '.') && (pathname[1] == PATH_SEP))
848f7cd7fe5SConrad Meyer return pathname + 2;
849f7cd7fe5SConrad Meyer return pathname;
850f7cd7fe5SConrad Meyer }
851f7cd7fe5SConrad Meyer
852f7cd7fe5SConrad Meyer static char*
trimLeadingCurrentDir(char * pathname)853f7cd7fe5SConrad Meyer trimLeadingCurrentDir(char *pathname)
854f7cd7fe5SConrad Meyer {
855f7cd7fe5SConrad Meyer /* 'union charunion' can do const-cast without compiler warning */
856f7cd7fe5SConrad Meyer union charunion {
857f7cd7fe5SConrad Meyer char *chr;
858f7cd7fe5SConrad Meyer const char* cchr;
859f7cd7fe5SConrad Meyer } ptr;
860f7cd7fe5SConrad Meyer ptr.cchr = trimLeadingCurrentDirConst(pathname);
861f7cd7fe5SConrad Meyer return ptr.chr;
862f7cd7fe5SConrad Meyer }
863f7cd7fe5SConrad Meyer
864f7cd7fe5SConrad Meyer /* remove leading './' or '/' chars here */
trimPath(const char * pathname)865f7cd7fe5SConrad Meyer static const char * trimPath(const char *pathname)
866f7cd7fe5SConrad Meyer {
867f7cd7fe5SConrad Meyer return trimLeadingRootChar(
868f7cd7fe5SConrad Meyer trimLeadingCurrentDirConst(pathname));
869f7cd7fe5SConrad Meyer }
870f7cd7fe5SConrad Meyer
mallocAndJoin2Dir(const char * dir1,const char * dir2)871f7cd7fe5SConrad Meyer static char* mallocAndJoin2Dir(const char *dir1, const char *dir2)
872f7cd7fe5SConrad Meyer {
873f7cd7fe5SConrad Meyer const size_t dir1Size = strlen(dir1);
874f7cd7fe5SConrad Meyer const size_t dir2Size = strlen(dir2);
875f7cd7fe5SConrad Meyer char *outDirBuffer, *buffer, trailingChar;
876f7cd7fe5SConrad Meyer
877f7cd7fe5SConrad Meyer assert(dir1 != NULL && dir2 != NULL);
878f7cd7fe5SConrad Meyer outDirBuffer = (char *) malloc(dir1Size + dir2Size + 2);
879f7cd7fe5SConrad Meyer CONTROL(outDirBuffer != NULL);
880f7cd7fe5SConrad Meyer
881f7cd7fe5SConrad Meyer memcpy(outDirBuffer, dir1, dir1Size);
882f7cd7fe5SConrad Meyer outDirBuffer[dir1Size] = '\0';
883f7cd7fe5SConrad Meyer
884f7cd7fe5SConrad Meyer if (dir2[0] == '.')
885f7cd7fe5SConrad Meyer return outDirBuffer;
886f7cd7fe5SConrad Meyer
887f7cd7fe5SConrad Meyer buffer = outDirBuffer + dir1Size;
888f7cd7fe5SConrad Meyer trailingChar = *(buffer - 1);
889f7cd7fe5SConrad Meyer if (trailingChar != PATH_SEP) {
890f7cd7fe5SConrad Meyer *buffer = PATH_SEP;
891f7cd7fe5SConrad Meyer buffer++;
892f7cd7fe5SConrad Meyer }
893f7cd7fe5SConrad Meyer memcpy(buffer, dir2, dir2Size);
894f7cd7fe5SConrad Meyer buffer[dir2Size] = '\0';
895f7cd7fe5SConrad Meyer
896f7cd7fe5SConrad Meyer return outDirBuffer;
897f7cd7fe5SConrad Meyer }
898f7cd7fe5SConrad Meyer
899f7cd7fe5SConrad Meyer /* this function will return NULL if input srcFileName is not valid name for mirrored output path */
UTIL_createMirroredDestDirName(const char * srcFileName,const char * outDirRootName)900f7cd7fe5SConrad Meyer char* UTIL_createMirroredDestDirName(const char* srcFileName, const char* outDirRootName)
901f7cd7fe5SConrad Meyer {
902f7cd7fe5SConrad Meyer char* pathname = NULL;
903f7cd7fe5SConrad Meyer if (!isFileNameValidForMirroredOutput(srcFileName))
904f7cd7fe5SConrad Meyer return NULL;
905f7cd7fe5SConrad Meyer
906f7cd7fe5SConrad Meyer pathname = mallocAndJoin2Dir(outDirRootName, trimPath(srcFileName));
907f7cd7fe5SConrad Meyer
908f7cd7fe5SConrad Meyer convertPathnameToDirName(pathname);
909f7cd7fe5SConrad Meyer return pathname;
910f7cd7fe5SConrad Meyer }
911f7cd7fe5SConrad Meyer
912f7cd7fe5SConrad Meyer static int
mirrorSrcDir(char * srcDirName,const char * outDirName)913f7cd7fe5SConrad Meyer mirrorSrcDir(char* srcDirName, const char* outDirName)
914f7cd7fe5SConrad Meyer {
915f7cd7fe5SConrad Meyer mode_t srcMode;
916f7cd7fe5SConrad Meyer int status = 0;
917f7cd7fe5SConrad Meyer char* newDir = mallocAndJoin2Dir(outDirName, trimPath(srcDirName));
918f7cd7fe5SConrad Meyer if (!newDir)
919f7cd7fe5SConrad Meyer return -ENOMEM;
920f7cd7fe5SConrad Meyer
921f7cd7fe5SConrad Meyer srcMode = getDirMode(srcDirName);
922f7cd7fe5SConrad Meyer status = makeDir(newDir, srcMode);
923f7cd7fe5SConrad Meyer free(newDir);
924f7cd7fe5SConrad Meyer return status;
925f7cd7fe5SConrad Meyer }
926f7cd7fe5SConrad Meyer
927f7cd7fe5SConrad Meyer static int
mirrorSrcDirRecursive(char * srcDirName,const char * outDirName)928f7cd7fe5SConrad Meyer mirrorSrcDirRecursive(char* srcDirName, const char* outDirName)
929f7cd7fe5SConrad Meyer {
930f7cd7fe5SConrad Meyer int status = 0;
931f7cd7fe5SConrad Meyer char* pp = trimLeadingCurrentDir(srcDirName);
932f7cd7fe5SConrad Meyer char* sp = NULL;
933f7cd7fe5SConrad Meyer
934f7cd7fe5SConrad Meyer while ((sp = strchr(pp, PATH_SEP)) != NULL) {
935f7cd7fe5SConrad Meyer if (sp != pp) {
936f7cd7fe5SConrad Meyer *sp = '\0';
937f7cd7fe5SConrad Meyer status = mirrorSrcDir(srcDirName, outDirName);
938f7cd7fe5SConrad Meyer if (status != 0)
939f7cd7fe5SConrad Meyer return status;
940f7cd7fe5SConrad Meyer *sp = PATH_SEP;
941f7cd7fe5SConrad Meyer }
942f7cd7fe5SConrad Meyer pp = sp + 1;
943f7cd7fe5SConrad Meyer }
944f7cd7fe5SConrad Meyer status = mirrorSrcDir(srcDirName, outDirName);
945f7cd7fe5SConrad Meyer return status;
946f7cd7fe5SConrad Meyer }
947f7cd7fe5SConrad Meyer
948f7cd7fe5SConrad Meyer static void
makeMirroredDestDirsWithSameSrcDirMode(char ** srcDirNames,unsigned nbFile,const char * outDirName)949f7cd7fe5SConrad Meyer makeMirroredDestDirsWithSameSrcDirMode(char** srcDirNames, unsigned nbFile, const char* outDirName)
950f7cd7fe5SConrad Meyer {
951f7cd7fe5SConrad Meyer unsigned int i = 0;
952f7cd7fe5SConrad Meyer for (i = 0; i < nbFile; i++)
953f7cd7fe5SConrad Meyer mirrorSrcDirRecursive(srcDirNames[i], outDirName);
954f7cd7fe5SConrad Meyer }
955f7cd7fe5SConrad Meyer
956f7cd7fe5SConrad Meyer static int
firstIsParentOrSameDirOfSecond(const char * firstDir,const char * secondDir)957f7cd7fe5SConrad Meyer firstIsParentOrSameDirOfSecond(const char* firstDir, const char* secondDir)
958f7cd7fe5SConrad Meyer {
959f7cd7fe5SConrad Meyer size_t firstDirLen = strlen(firstDir),
960f7cd7fe5SConrad Meyer secondDirLen = strlen(secondDir);
961f7cd7fe5SConrad Meyer return firstDirLen <= secondDirLen &&
962f7cd7fe5SConrad Meyer (secondDir[firstDirLen] == PATH_SEP || secondDir[firstDirLen] == '\0') &&
963f7cd7fe5SConrad Meyer 0 == strncmp(firstDir, secondDir, firstDirLen);
964f7cd7fe5SConrad Meyer }
965f7cd7fe5SConrad Meyer
compareDir(const void * pathname1,const void * pathname2)966f7cd7fe5SConrad Meyer static int compareDir(const void* pathname1, const void* pathname2) {
967f7cd7fe5SConrad Meyer /* sort it after remove the leading '/' or './'*/
968f7cd7fe5SConrad Meyer const char* s1 = trimPath(*(char * const *) pathname1);
969f7cd7fe5SConrad Meyer const char* s2 = trimPath(*(char * const *) pathname2);
970f7cd7fe5SConrad Meyer return strcmp(s1, s2);
971f7cd7fe5SConrad Meyer }
972f7cd7fe5SConrad Meyer
973f7cd7fe5SConrad Meyer static void
makeUniqueMirroredDestDirs(char ** srcDirNames,unsigned nbFile,const char * outDirName)974f7cd7fe5SConrad Meyer makeUniqueMirroredDestDirs(char** srcDirNames, unsigned nbFile, const char* outDirName)
975f7cd7fe5SConrad Meyer {
976f7cd7fe5SConrad Meyer unsigned int i = 0, uniqueDirNr = 0;
977f7cd7fe5SConrad Meyer char** uniqueDirNames = NULL;
978f7cd7fe5SConrad Meyer
979f7cd7fe5SConrad Meyer if (nbFile == 0)
980f7cd7fe5SConrad Meyer return;
981f7cd7fe5SConrad Meyer
982f7cd7fe5SConrad Meyer uniqueDirNames = (char** ) malloc(nbFile * sizeof (char *));
983f7cd7fe5SConrad Meyer CONTROL(uniqueDirNames != NULL);
984f7cd7fe5SConrad Meyer
985f7cd7fe5SConrad Meyer /* if dirs is "a/b/c" and "a/b/c/d", we only need call:
986f7cd7fe5SConrad Meyer * we just need "a/b/c/d" */
987f7cd7fe5SConrad Meyer qsort((void *)srcDirNames, nbFile, sizeof(char*), compareDir);
988f7cd7fe5SConrad Meyer
989f7cd7fe5SConrad Meyer uniqueDirNr = 1;
990f7cd7fe5SConrad Meyer uniqueDirNames[uniqueDirNr - 1] = srcDirNames[0];
991f7cd7fe5SConrad Meyer for (i = 1; i < nbFile; i++) {
992f7cd7fe5SConrad Meyer char* prevDirName = srcDirNames[i - 1];
993f7cd7fe5SConrad Meyer char* currDirName = srcDirNames[i];
994f7cd7fe5SConrad Meyer
995*5ff13fbcSAllan Jude /* note: we always compare trimmed path, i.e.:
996f7cd7fe5SConrad Meyer * src dir of "./foo" and "/foo" will be both saved into:
997f7cd7fe5SConrad Meyer * "outDirName/foo/" */
998f7cd7fe5SConrad Meyer if (!firstIsParentOrSameDirOfSecond(trimPath(prevDirName),
999f7cd7fe5SConrad Meyer trimPath(currDirName)))
1000f7cd7fe5SConrad Meyer uniqueDirNr++;
1001f7cd7fe5SConrad Meyer
1002f7cd7fe5SConrad Meyer /* we need maintain original src dir name instead of trimmed
1003*5ff13fbcSAllan Jude * dir, so we can retrieve the original src dir's mode_t */
1004f7cd7fe5SConrad Meyer uniqueDirNames[uniqueDirNr - 1] = currDirName;
1005f7cd7fe5SConrad Meyer }
1006f7cd7fe5SConrad Meyer
1007f7cd7fe5SConrad Meyer makeMirroredDestDirsWithSameSrcDirMode(uniqueDirNames, uniqueDirNr, outDirName);
1008f7cd7fe5SConrad Meyer
1009f7cd7fe5SConrad Meyer free(uniqueDirNames);
1010f7cd7fe5SConrad Meyer }
1011f7cd7fe5SConrad Meyer
1012f7cd7fe5SConrad Meyer static void
makeMirroredDestDirs(char ** srcFileNames,unsigned nbFile,const char * outDirName)1013f7cd7fe5SConrad Meyer makeMirroredDestDirs(char** srcFileNames, unsigned nbFile, const char* outDirName)
1014f7cd7fe5SConrad Meyer {
1015f7cd7fe5SConrad Meyer unsigned int i = 0;
1016f7cd7fe5SConrad Meyer for (i = 0; i < nbFile; ++i)
1017f7cd7fe5SConrad Meyer convertPathnameToDirName(srcFileNames[i]);
1018f7cd7fe5SConrad Meyer makeUniqueMirroredDestDirs(srcFileNames, nbFile, outDirName);
1019f7cd7fe5SConrad Meyer }
1020f7cd7fe5SConrad Meyer
UTIL_mirrorSourceFilesDirectories(const char ** inFileNames,unsigned int nbFile,const char * outDirName)1021f7cd7fe5SConrad Meyer void UTIL_mirrorSourceFilesDirectories(const char** inFileNames, unsigned int nbFile, const char* outDirName)
1022f7cd7fe5SConrad Meyer {
1023f7cd7fe5SConrad Meyer unsigned int i = 0, validFilenamesNr = 0;
1024f7cd7fe5SConrad Meyer char** srcFileNames = (char **) malloc(nbFile * sizeof (char *));
1025f7cd7fe5SConrad Meyer CONTROL(srcFileNames != NULL);
1026f7cd7fe5SConrad Meyer
1027f7cd7fe5SConrad Meyer /* check input filenames is valid */
1028f7cd7fe5SConrad Meyer for (i = 0; i < nbFile; ++i) {
1029f7cd7fe5SConrad Meyer if (isFileNameValidForMirroredOutput(inFileNames[i])) {
1030f7cd7fe5SConrad Meyer char* fname = STRDUP(inFileNames[i]);
1031f7cd7fe5SConrad Meyer CONTROL(fname != NULL);
1032f7cd7fe5SConrad Meyer srcFileNames[validFilenamesNr++] = fname;
1033f7cd7fe5SConrad Meyer }
1034f7cd7fe5SConrad Meyer }
1035f7cd7fe5SConrad Meyer
1036f7cd7fe5SConrad Meyer if (validFilenamesNr > 0) {
1037f7cd7fe5SConrad Meyer makeDir(outDirName, DIR_DEFAULT_MODE);
1038f7cd7fe5SConrad Meyer makeMirroredDestDirs(srcFileNames, validFilenamesNr, outDirName);
1039f7cd7fe5SConrad Meyer }
1040f7cd7fe5SConrad Meyer
1041f7cd7fe5SConrad Meyer for (i = 0; i < validFilenamesNr; i++)
1042f7cd7fe5SConrad Meyer free(srcFileNames[i]);
1043f7cd7fe5SConrad Meyer free(srcFileNames);
1044f7cd7fe5SConrad Meyer }
104537f1f268SConrad Meyer
104637f1f268SConrad Meyer FileNamesTable*
UTIL_createExpandedFNT(const char * const * inputNames,size_t nbIfns,int followLinks)1047*5ff13fbcSAllan Jude UTIL_createExpandedFNT(const char* const* inputNames, size_t nbIfns, int followLinks)
1048a0483764SConrad Meyer {
104937f1f268SConrad Meyer unsigned nbFiles;
1050a0483764SConrad Meyer char* buf = (char*)malloc(LIST_SIZE_INCREASE);
1051a0483764SConrad Meyer char* bufend = buf + LIST_SIZE_INCREASE;
1052a0483764SConrad Meyer
1053a0483764SConrad Meyer if (!buf) return NULL;
1054a0483764SConrad Meyer
105537f1f268SConrad Meyer { size_t ifnNb, pos;
105637f1f268SConrad Meyer for (ifnNb=0, pos=0, nbFiles=0; ifnNb<nbIfns; ifnNb++) {
105737f1f268SConrad Meyer if (!UTIL_isDirectory(inputNames[ifnNb])) {
105837f1f268SConrad Meyer size_t const len = strlen(inputNames[ifnNb]);
1059a0483764SConrad Meyer if (buf + pos + len >= bufend) {
1060a0483764SConrad Meyer ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE;
10619cbefe25SConrad Meyer assert(newListSize >= 0);
10629cbefe25SConrad Meyer buf = (char*)UTIL_realloc(buf, (size_t)newListSize);
1063a0483764SConrad Meyer if (!buf) return NULL;
106437f1f268SConrad Meyer bufend = buf + newListSize;
1065a0483764SConrad Meyer }
1066a0483764SConrad Meyer if (buf + pos + len < bufend) {
106737f1f268SConrad Meyer memcpy(buf+pos, inputNames[ifnNb], len+1); /* including final \0 */
1068a0483764SConrad Meyer pos += len + 1;
1069a0483764SConrad Meyer nbFiles++;
1070a0483764SConrad Meyer }
1071a0483764SConrad Meyer } else {
107237f1f268SConrad Meyer nbFiles += (unsigned)UTIL_prepareFileList(inputNames[ifnNb], &buf, &pos, &bufend, followLinks);
1073a0483764SConrad Meyer if (buf == NULL) return NULL;
107437f1f268SConrad Meyer } } }
1075a0483764SConrad Meyer
107637f1f268SConrad Meyer /* note : even if nbFiles==0, function returns a valid, though empty, FileNamesTable* object */
1077a0483764SConrad Meyer
107837f1f268SConrad Meyer { size_t ifnNb, pos;
107937f1f268SConrad Meyer size_t const fntCapacity = nbFiles + 1; /* minimum 1, allows adding one reference, typically stdin */
108037f1f268SConrad Meyer const char** const fileNamesTable = (const char**)malloc(fntCapacity * sizeof(*fileNamesTable));
108137f1f268SConrad Meyer if (!fileNamesTable) { free(buf); return NULL; }
1082a0483764SConrad Meyer
108337f1f268SConrad Meyer for (ifnNb = 0, pos = 0; ifnNb < nbFiles; ifnNb++) {
108437f1f268SConrad Meyer fileNamesTable[ifnNb] = buf + pos;
108537f1f268SConrad Meyer if (buf + pos > bufend) { free(buf); free((void*)fileNamesTable); return NULL; }
108637f1f268SConrad Meyer pos += strlen(fileNamesTable[ifnNb]) + 1;
1087a0483764SConrad Meyer }
108837f1f268SConrad Meyer return UTIL_assembleFileNamesTable2(fileNamesTable, nbFiles, fntCapacity, buf);
1089a0483764SConrad Meyer }
10909cbefe25SConrad Meyer }
1091a0483764SConrad Meyer
10922b9c00cbSConrad Meyer
UTIL_expandFNT(FileNamesTable ** fnt,int followLinks)109337f1f268SConrad Meyer void UTIL_expandFNT(FileNamesTable** fnt, int followLinks)
109437f1f268SConrad Meyer {
109537f1f268SConrad Meyer FileNamesTable* const newFNT = UTIL_createExpandedFNT((*fnt)->fileNames, (*fnt)->tableSize, followLinks);
109637f1f268SConrad Meyer CONTROL(newFNT != NULL);
109737f1f268SConrad Meyer UTIL_freeFileNamesTable(*fnt);
109837f1f268SConrad Meyer *fnt = newFNT;
109937f1f268SConrad Meyer }
1100a0483764SConrad Meyer
UTIL_createFNT_fromROTable(const char ** filenames,size_t nbFilenames)110137f1f268SConrad Meyer FileNamesTable* UTIL_createFNT_fromROTable(const char** filenames, size_t nbFilenames)
110237f1f268SConrad Meyer {
110337f1f268SConrad Meyer size_t const sizeof_FNTable = nbFilenames * sizeof(*filenames);
110437f1f268SConrad Meyer const char** const newFNTable = (const char**)malloc(sizeof_FNTable);
110537f1f268SConrad Meyer if (newFNTable==NULL) return NULL;
110637f1f268SConrad Meyer memcpy((void*)newFNTable, filenames, sizeof_FNTable); /* void* : mitigate a Visual compiler bug or limitation */
110737f1f268SConrad Meyer return UTIL_assembleFileNamesTable(newFNTable, nbFilenames, NULL);
110837f1f268SConrad Meyer }
1109a0483764SConrad Meyer
11102b9c00cbSConrad Meyer
1111a0483764SConrad Meyer /*-****************************************
1112*5ff13fbcSAllan Jude * count the number of cores
1113a0483764SConrad Meyer ******************************************/
1114a0483764SConrad Meyer
1115a0483764SConrad Meyer #if defined(_WIN32) || defined(WIN32)
1116a0483764SConrad Meyer
1117a0483764SConrad Meyer #include <windows.h>
1118a0483764SConrad Meyer
1119a0483764SConrad Meyer typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
1120a0483764SConrad Meyer
CountSetBits(ULONG_PTR bitMask)1121*5ff13fbcSAllan Jude DWORD CountSetBits(ULONG_PTR bitMask)
1122a0483764SConrad Meyer {
1123*5ff13fbcSAllan Jude DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;
1124*5ff13fbcSAllan Jude DWORD bitSetCount = 0;
1125*5ff13fbcSAllan Jude ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;
1126*5ff13fbcSAllan Jude DWORD i;
1127*5ff13fbcSAllan Jude
1128*5ff13fbcSAllan Jude for (i = 0; i <= LSHIFT; ++i)
1129*5ff13fbcSAllan Jude {
1130*5ff13fbcSAllan Jude bitSetCount += ((bitMask & bitTest)?1:0);
1131*5ff13fbcSAllan Jude bitTest/=2;
1132*5ff13fbcSAllan Jude }
1133*5ff13fbcSAllan Jude
1134*5ff13fbcSAllan Jude return bitSetCount;
1135*5ff13fbcSAllan Jude }
1136*5ff13fbcSAllan Jude
UTIL_countCores(int logical)1137*5ff13fbcSAllan Jude int UTIL_countCores(int logical)
1138*5ff13fbcSAllan Jude {
1139*5ff13fbcSAllan Jude static int numCores = 0;
1140*5ff13fbcSAllan Jude if (numCores != 0) return numCores;
1141a0483764SConrad Meyer
1142a0483764SConrad Meyer { LPFN_GLPI glpi;
1143a0483764SConrad Meyer BOOL done = FALSE;
1144a0483764SConrad Meyer PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
1145a0483764SConrad Meyer PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
1146a0483764SConrad Meyer DWORD returnLength = 0;
1147a0483764SConrad Meyer size_t byteOffset = 0;
1148a0483764SConrad Meyer
11499cbefe25SConrad Meyer #if defined(_MSC_VER)
11509cbefe25SConrad Meyer /* Visual Studio does not like the following cast */
11519cbefe25SConrad Meyer # pragma warning( disable : 4054 ) /* conversion from function ptr to data ptr */
11529cbefe25SConrad Meyer # pragma warning( disable : 4055 ) /* conversion from data ptr to function ptr */
11539cbefe25SConrad Meyer #endif
11549cbefe25SConrad Meyer glpi = (LPFN_GLPI)(void*)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
1155a0483764SConrad Meyer "GetLogicalProcessorInformation");
1156a0483764SConrad Meyer
1157a0483764SConrad Meyer if (glpi == NULL) {
1158a0483764SConrad Meyer goto failed;
1159a0483764SConrad Meyer }
1160a0483764SConrad Meyer
1161a0483764SConrad Meyer while(!done) {
1162a0483764SConrad Meyer DWORD rc = glpi(buffer, &returnLength);
1163a0483764SConrad Meyer if (FALSE == rc) {
1164a0483764SConrad Meyer if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1165a0483764SConrad Meyer if (buffer)
1166a0483764SConrad Meyer free(buffer);
1167a0483764SConrad Meyer buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
1168a0483764SConrad Meyer
1169a0483764SConrad Meyer if (buffer == NULL) {
1170a0483764SConrad Meyer perror("zstd");
1171a0483764SConrad Meyer exit(1);
1172a0483764SConrad Meyer }
1173a0483764SConrad Meyer } else {
1174a0483764SConrad Meyer /* some other error */
1175a0483764SConrad Meyer goto failed;
1176a0483764SConrad Meyer }
1177a0483764SConrad Meyer } else {
1178a0483764SConrad Meyer done = TRUE;
117937f1f268SConrad Meyer } }
1180a0483764SConrad Meyer
1181a0483764SConrad Meyer ptr = buffer;
1182a0483764SConrad Meyer
1183a0483764SConrad Meyer while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
1184a0483764SConrad Meyer
1185a0483764SConrad Meyer if (ptr->Relationship == RelationProcessorCore) {
1186*5ff13fbcSAllan Jude if (logical)
1187*5ff13fbcSAllan Jude numCores += CountSetBits(ptr->ProcessorMask);
1188*5ff13fbcSAllan Jude else
1189*5ff13fbcSAllan Jude numCores++;
1190a0483764SConrad Meyer }
1191a0483764SConrad Meyer
1192a0483764SConrad Meyer ptr++;
1193a0483764SConrad Meyer byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
1194a0483764SConrad Meyer }
1195a0483764SConrad Meyer
1196a0483764SConrad Meyer free(buffer);
1197a0483764SConrad Meyer
1198*5ff13fbcSAllan Jude return numCores;
1199a0483764SConrad Meyer }
1200a0483764SConrad Meyer
1201a0483764SConrad Meyer failed:
1202a0483764SConrad Meyer /* try to fall back on GetSystemInfo */
1203a0483764SConrad Meyer { SYSTEM_INFO sysinfo;
1204a0483764SConrad Meyer GetSystemInfo(&sysinfo);
1205*5ff13fbcSAllan Jude numCores = sysinfo.dwNumberOfProcessors;
1206*5ff13fbcSAllan Jude if (numCores == 0) numCores = 1; /* just in case */
1207a0483764SConrad Meyer }
1208*5ff13fbcSAllan Jude return numCores;
1209a0483764SConrad Meyer }
1210a0483764SConrad Meyer
1211a0483764SConrad Meyer #elif defined(__APPLE__)
1212a0483764SConrad Meyer
1213a0483764SConrad Meyer #include <sys/sysctl.h>
1214a0483764SConrad Meyer
1215a0483764SConrad Meyer /* Use apple-provided syscall
1216a0483764SConrad Meyer * see: man 3 sysctl */
UTIL_countCores(int logical)1217*5ff13fbcSAllan Jude int UTIL_countCores(int logical)
1218a0483764SConrad Meyer {
1219*5ff13fbcSAllan Jude static S32 numCores = 0; /* apple specifies int32_t */
1220*5ff13fbcSAllan Jude if (numCores != 0) return numCores;
1221a0483764SConrad Meyer
1222a0483764SConrad Meyer { size_t size = sizeof(S32);
1223*5ff13fbcSAllan Jude int const ret = sysctlbyname(logical ? "hw.logicalcpu" : "hw.physicalcpu", &numCores, &size, NULL, 0);
1224a0483764SConrad Meyer if (ret != 0) {
1225a0483764SConrad Meyer if (errno == ENOENT) {
1226a0483764SConrad Meyer /* entry not present, fall back on 1 */
1227*5ff13fbcSAllan Jude numCores = 1;
1228a0483764SConrad Meyer } else {
1229*5ff13fbcSAllan Jude perror("zstd: can't get number of cpus");
1230a0483764SConrad Meyer exit(1);
1231a0483764SConrad Meyer }
1232a0483764SConrad Meyer }
1233a0483764SConrad Meyer
1234*5ff13fbcSAllan Jude return numCores;
1235a0483764SConrad Meyer }
1236a0483764SConrad Meyer }
1237a0483764SConrad Meyer
1238a0483764SConrad Meyer #elif defined(__linux__)
1239a0483764SConrad Meyer
1240a0483764SConrad Meyer /* parse /proc/cpuinfo
1241a0483764SConrad Meyer * siblings / cpu cores should give hyperthreading ratio
1242a0483764SConrad Meyer * otherwise fall back on sysconf */
UTIL_countCores(int logical)1243*5ff13fbcSAllan Jude int UTIL_countCores(int logical)
1244a0483764SConrad Meyer {
1245*5ff13fbcSAllan Jude static int numCores = 0;
1246a0483764SConrad Meyer
1247*5ff13fbcSAllan Jude if (numCores != 0) return numCores;
1248a0483764SConrad Meyer
1249*5ff13fbcSAllan Jude numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
1250*5ff13fbcSAllan Jude if (numCores == -1) {
1251a0483764SConrad Meyer /* value not queryable, fall back on 1 */
1252*5ff13fbcSAllan Jude return numCores = 1;
1253a0483764SConrad Meyer }
1254a0483764SConrad Meyer
1255a0483764SConrad Meyer /* try to determine if there's hyperthreading */
1256a0483764SConrad Meyer { FILE* const cpuinfo = fopen("/proc/cpuinfo", "r");
1257a0483764SConrad Meyer #define BUF_SIZE 80
1258a0483764SConrad Meyer char buff[BUF_SIZE];
1259a0483764SConrad Meyer
1260a0483764SConrad Meyer int siblings = 0;
1261a0483764SConrad Meyer int cpu_cores = 0;
1262a0483764SConrad Meyer int ratio = 1;
1263a0483764SConrad Meyer
1264a0483764SConrad Meyer if (cpuinfo == NULL) {
1265a0483764SConrad Meyer /* fall back on the sysconf value */
1266*5ff13fbcSAllan Jude return numCores;
1267a0483764SConrad Meyer }
1268a0483764SConrad Meyer
1269a0483764SConrad Meyer /* assume the cpu cores/siblings values will be constant across all
1270a0483764SConrad Meyer * present processors */
1271a0483764SConrad Meyer while (!feof(cpuinfo)) {
1272a0483764SConrad Meyer if (fgets(buff, BUF_SIZE, cpuinfo) != NULL) {
1273a0483764SConrad Meyer if (strncmp(buff, "siblings", 8) == 0) {
1274a0483764SConrad Meyer const char* const sep = strchr(buff, ':');
12759cbefe25SConrad Meyer if (sep == NULL || *sep == '\0') {
1276a0483764SConrad Meyer /* formatting was broken? */
1277a0483764SConrad Meyer goto failed;
1278a0483764SConrad Meyer }
1279a0483764SConrad Meyer
1280a0483764SConrad Meyer siblings = atoi(sep + 1);
1281a0483764SConrad Meyer }
1282a0483764SConrad Meyer if (strncmp(buff, "cpu cores", 9) == 0) {
1283a0483764SConrad Meyer const char* const sep = strchr(buff, ':');
12849cbefe25SConrad Meyer if (sep == NULL || *sep == '\0') {
1285a0483764SConrad Meyer /* formatting was broken? */
1286a0483764SConrad Meyer goto failed;
1287a0483764SConrad Meyer }
1288a0483764SConrad Meyer
1289a0483764SConrad Meyer cpu_cores = atoi(sep + 1);
1290a0483764SConrad Meyer }
1291a0483764SConrad Meyer } else if (ferror(cpuinfo)) {
1292a0483764SConrad Meyer /* fall back on the sysconf value */
1293a0483764SConrad Meyer goto failed;
129437f1f268SConrad Meyer } }
1295*5ff13fbcSAllan Jude if (siblings && cpu_cores && siblings > cpu_cores) {
1296a0483764SConrad Meyer ratio = siblings / cpu_cores;
1297a0483764SConrad Meyer }
1298*5ff13fbcSAllan Jude
1299*5ff13fbcSAllan Jude if (ratio && numCores > ratio && !logical) {
1300*5ff13fbcSAllan Jude numCores = numCores / ratio;
1301*5ff13fbcSAllan Jude }
1302*5ff13fbcSAllan Jude
1303a0483764SConrad Meyer failed:
1304a0483764SConrad Meyer fclose(cpuinfo);
1305*5ff13fbcSAllan Jude return numCores;
1306a0483764SConrad Meyer }
1307a0483764SConrad Meyer }
1308a0483764SConrad Meyer
13092b9c00cbSConrad Meyer #elif defined(__FreeBSD__)
1310a0483764SConrad Meyer
13112b9c00cbSConrad Meyer #include <sys/param.h>
13122b9c00cbSConrad Meyer #include <sys/sysctl.h>
13132b9c00cbSConrad Meyer
13142b9c00cbSConrad Meyer /* Use physical core sysctl when available
13152b9c00cbSConrad Meyer * see: man 4 smp, man 3 sysctl */
UTIL_countCores(int logical)1316*5ff13fbcSAllan Jude int UTIL_countCores(int logical)
13172b9c00cbSConrad Meyer {
1318*5ff13fbcSAllan Jude static int numCores = 0; /* freebsd sysctl is native int sized */
1319*5ff13fbcSAllan Jude #if __FreeBSD_version >= 1300008
1320*5ff13fbcSAllan Jude static int perCore = 1;
1321*5ff13fbcSAllan Jude #endif
1322*5ff13fbcSAllan Jude if (numCores != 0) return numCores;
13232b9c00cbSConrad Meyer
13242b9c00cbSConrad Meyer #if __FreeBSD_version >= 1300008
1325*5ff13fbcSAllan Jude { size_t size = sizeof(numCores);
1326*5ff13fbcSAllan Jude int ret = sysctlbyname("kern.smp.cores", &numCores, &size, NULL, 0);
1327*5ff13fbcSAllan Jude if (ret == 0) {
1328*5ff13fbcSAllan Jude if (logical) {
1329*5ff13fbcSAllan Jude ret = sysctlbyname("kern.smp.threads_per_core", &perCore, &size, NULL, 0);
1330*5ff13fbcSAllan Jude /* default to physical cores if logical cannot be read */
1331*5ff13fbcSAllan Jude if (ret == 0)
1332*5ff13fbcSAllan Jude numCores *= perCore;
1333*5ff13fbcSAllan Jude }
1334*5ff13fbcSAllan Jude
1335*5ff13fbcSAllan Jude return numCores;
1336*5ff13fbcSAllan Jude }
13372b9c00cbSConrad Meyer if (errno != ENOENT) {
1338*5ff13fbcSAllan Jude perror("zstd: can't get number of cpus");
13392b9c00cbSConrad Meyer exit(1);
13402b9c00cbSConrad Meyer }
13412b9c00cbSConrad Meyer /* sysctl not present, fall through to older sysconf method */
13422b9c00cbSConrad Meyer }
1343*5ff13fbcSAllan Jude #else
1344*5ff13fbcSAllan Jude /* suppress unused parameter warning */
1345*5ff13fbcSAllan Jude (void) logical;
13462b9c00cbSConrad Meyer #endif
13472b9c00cbSConrad Meyer
1348*5ff13fbcSAllan Jude numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
1349*5ff13fbcSAllan Jude if (numCores == -1) {
13502b9c00cbSConrad Meyer /* value not queryable, fall back on 1 */
1351*5ff13fbcSAllan Jude numCores = 1;
13522b9c00cbSConrad Meyer }
1353*5ff13fbcSAllan Jude return numCores;
13542b9c00cbSConrad Meyer }
13552b9c00cbSConrad Meyer
135637f1f268SConrad Meyer #elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
13572b9c00cbSConrad Meyer
13582b9c00cbSConrad Meyer /* Use POSIX sysconf
13592b9c00cbSConrad Meyer * see: man 3 sysconf */
UTIL_countCores(int logical)1360*5ff13fbcSAllan Jude int UTIL_countCores(int logical)
1361a0483764SConrad Meyer {
1362*5ff13fbcSAllan Jude static int numCores = 0;
1363a0483764SConrad Meyer
1364*5ff13fbcSAllan Jude /* suppress unused parameter warning */
1365*5ff13fbcSAllan Jude (void)logical;
1366a0483764SConrad Meyer
1367*5ff13fbcSAllan Jude if (numCores != 0) return numCores;
1368*5ff13fbcSAllan Jude
1369*5ff13fbcSAllan Jude numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
1370*5ff13fbcSAllan Jude if (numCores == -1) {
1371a0483764SConrad Meyer /* value not queryable, fall back on 1 */
1372*5ff13fbcSAllan Jude return numCores = 1;
1373a0483764SConrad Meyer }
1374*5ff13fbcSAllan Jude return numCores;
1375a0483764SConrad Meyer }
1376a0483764SConrad Meyer
1377a0483764SConrad Meyer #else
1378a0483764SConrad Meyer
UTIL_countCores(int logical)1379*5ff13fbcSAllan Jude int UTIL_countCores(int logical)
1380a0483764SConrad Meyer {
1381a0483764SConrad Meyer /* assume 1 */
1382a0483764SConrad Meyer return 1;
1383a0483764SConrad Meyer }
1384a0483764SConrad Meyer
1385a0483764SConrad Meyer #endif
1386a0483764SConrad Meyer
UTIL_countPhysicalCores(void)1387*5ff13fbcSAllan Jude int UTIL_countPhysicalCores(void)
1388*5ff13fbcSAllan Jude {
1389*5ff13fbcSAllan Jude return UTIL_countCores(0);
1390*5ff13fbcSAllan Jude }
1391*5ff13fbcSAllan Jude
UTIL_countLogicalCores(void)1392*5ff13fbcSAllan Jude int UTIL_countLogicalCores(void)
1393*5ff13fbcSAllan Jude {
1394*5ff13fbcSAllan Jude return UTIL_countCores(1);
1395*5ff13fbcSAllan Jude }
1396*5ff13fbcSAllan Jude
1397a0483764SConrad Meyer #if defined (__cplusplus)
1398a0483764SConrad Meyer }
1399a0483764SConrad Meyer #endif
1400