xref: /freebsd/sys/contrib/zstd/programs/util.c (revision 9cbefe25d46756f342c7dd3d174d2d1103808f21)
1a0483764SConrad Meyer /*
2a0483764SConrad Meyer  * Copyright (c) 2016-present, 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 ! */
20a0483764SConrad Meyer #include <errno.h>
21a0483764SConrad Meyer #include <assert.h>
22a0483764SConrad Meyer 
23*9cbefe25SConrad Meyer #if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
24*9cbefe25SConrad Meyer #include <direct.h>     /* needed for _mkdir in windows */
25*9cbefe25SConrad Meyer #endif
26a0483764SConrad Meyer 
27a0483764SConrad Meyer int UTIL_fileExist(const char* filename)
28a0483764SConrad Meyer {
29a0483764SConrad Meyer     stat_t statbuf;
30a0483764SConrad Meyer #if defined(_MSC_VER)
31a0483764SConrad Meyer     int const stat_error = _stat64(filename, &statbuf);
32a0483764SConrad Meyer #else
33a0483764SConrad Meyer     int const stat_error = stat(filename, &statbuf);
34a0483764SConrad Meyer #endif
35a0483764SConrad Meyer     return !stat_error;
36a0483764SConrad Meyer }
37a0483764SConrad Meyer 
38a0483764SConrad Meyer int UTIL_isRegularFile(const char* infilename)
39a0483764SConrad Meyer {
40a0483764SConrad Meyer     stat_t statbuf;
41a0483764SConrad Meyer     return UTIL_getFileStat(infilename, &statbuf); /* Only need to know whether it is a regular file */
42a0483764SConrad Meyer }
43a0483764SConrad Meyer 
44a0483764SConrad Meyer int UTIL_getFileStat(const char* infilename, stat_t *statbuf)
45a0483764SConrad Meyer {
46a0483764SConrad Meyer     int r;
47a0483764SConrad Meyer #if defined(_MSC_VER)
48a0483764SConrad Meyer     r = _stat64(infilename, statbuf);
49a0483764SConrad Meyer     if (r || !(statbuf->st_mode & S_IFREG)) return 0;   /* No good... */
50a0483764SConrad Meyer #else
51a0483764SConrad Meyer     r = stat(infilename, statbuf);
52a0483764SConrad Meyer     if (r || !S_ISREG(statbuf->st_mode)) return 0;   /* No good... */
53a0483764SConrad Meyer #endif
54a0483764SConrad Meyer     return 1;
55a0483764SConrad Meyer }
56a0483764SConrad Meyer 
57a0483764SConrad Meyer int UTIL_setFileStat(const char *filename, stat_t *statbuf)
58a0483764SConrad Meyer {
59a0483764SConrad Meyer     int res = 0;
60a0483764SConrad Meyer 
61a0483764SConrad Meyer     if (!UTIL_isRegularFile(filename))
62a0483764SConrad Meyer         return -1;
63a0483764SConrad Meyer 
64*9cbefe25SConrad Meyer     /* set access and modification times */
65*9cbefe25SConrad Meyer #if defined(_WIN32) || (PLATFORM_POSIX_VERSION < 200809L)
66*9cbefe25SConrad Meyer     {
67*9cbefe25SConrad Meyer         struct utimbuf timebuf;
68a0483764SConrad Meyer         timebuf.actime = time(NULL);
69a0483764SConrad Meyer         timebuf.modtime = statbuf->st_mtime;
70*9cbefe25SConrad Meyer         res += utime(filename, &timebuf);
71*9cbefe25SConrad Meyer     }
72*9cbefe25SConrad Meyer #else
73*9cbefe25SConrad Meyer     {
74*9cbefe25SConrad Meyer         /* (atime, mtime) */
75*9cbefe25SConrad Meyer         struct timespec timebuf[2] = { {0, UTIME_NOW} };
76*9cbefe25SConrad Meyer         timebuf[1] = statbuf->st_mtim;
77*9cbefe25SConrad Meyer         res += utimensat(AT_FDCWD, filename, timebuf, 0);
78*9cbefe25SConrad Meyer     }
79*9cbefe25SConrad Meyer #endif
80a0483764SConrad Meyer 
81a0483764SConrad Meyer #if !defined(_WIN32)
82a0483764SConrad Meyer     res += chown(filename, statbuf->st_uid, statbuf->st_gid);  /* Copy ownership */
83a0483764SConrad Meyer #endif
84a0483764SConrad Meyer 
85a0483764SConrad Meyer     res += chmod(filename, statbuf->st_mode & 07777);  /* Copy file permissions */
86a0483764SConrad Meyer 
87a0483764SConrad Meyer     errno = 0;
88a0483764SConrad Meyer     return -res; /* number of errors is returned */
89a0483764SConrad Meyer }
90a0483764SConrad Meyer 
91a0483764SConrad Meyer U32 UTIL_isDirectory(const char* infilename)
92a0483764SConrad Meyer {
93a0483764SConrad Meyer     int r;
94a0483764SConrad Meyer     stat_t statbuf;
95a0483764SConrad Meyer #if defined(_MSC_VER)
96a0483764SConrad Meyer     r = _stat64(infilename, &statbuf);
97a0483764SConrad Meyer     if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
98a0483764SConrad Meyer #else
99a0483764SConrad Meyer     r = stat(infilename, &statbuf);
100a0483764SConrad Meyer     if (!r && S_ISDIR(statbuf.st_mode)) return 1;
101a0483764SConrad Meyer #endif
102a0483764SConrad Meyer     return 0;
103a0483764SConrad Meyer }
104a0483764SConrad Meyer 
105*9cbefe25SConrad Meyer int UTIL_compareStr(const void *p1, const void *p2) {
106*9cbefe25SConrad Meyer     return strcmp(* (char * const *) p1, * (char * const *) p2);
107*9cbefe25SConrad Meyer }
108*9cbefe25SConrad Meyer 
109*9cbefe25SConrad Meyer int UTIL_isSameFile(const char* fName1, const char* fName2)
1102b9c00cbSConrad Meyer {
111*9cbefe25SConrad Meyer     assert(fName1 != NULL); assert(fName2 != NULL);
112*9cbefe25SConrad Meyer #if defined(_MSC_VER) || defined(_WIN32)
1132b9c00cbSConrad Meyer     /* note : Visual does not support file identification by inode.
114*9cbefe25SConrad Meyer      *        inode does not work on Windows, even with a posix layer, like msys2.
1152b9c00cbSConrad Meyer      *        The following work-around is limited to detecting exact name repetition only,
1162b9c00cbSConrad Meyer      *        aka `filename` is considered different from `subdir/../filename` */
117*9cbefe25SConrad Meyer     return !strcmp(fName1, fName2);
1182b9c00cbSConrad Meyer #else
119*9cbefe25SConrad Meyer     {   stat_t file1Stat;
1202b9c00cbSConrad Meyer         stat_t file2Stat;
121*9cbefe25SConrad Meyer         return UTIL_getFileStat(fName1, &file1Stat)
122*9cbefe25SConrad Meyer             && UTIL_getFileStat(fName2, &file2Stat)
1232b9c00cbSConrad Meyer             && (file1Stat.st_dev == file2Stat.st_dev)
1242b9c00cbSConrad Meyer             && (file1Stat.st_ino == file2Stat.st_ino);
125*9cbefe25SConrad Meyer     }
1262b9c00cbSConrad Meyer #endif
1272b9c00cbSConrad Meyer }
1282b9c00cbSConrad Meyer 
129*9cbefe25SConrad Meyer #ifndef _MSC_VER
130*9cbefe25SConrad Meyer /* Using this to distinguish named pipes */
131*9cbefe25SConrad Meyer U32 UTIL_isFIFO(const char* infilename)
132*9cbefe25SConrad Meyer {
133*9cbefe25SConrad Meyer /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
134*9cbefe25SConrad Meyer #if PLATFORM_POSIX_VERSION >= 200112L
135*9cbefe25SConrad Meyer     stat_t statbuf;
136*9cbefe25SConrad Meyer     int r = UTIL_getFileStat(infilename, &statbuf);
137*9cbefe25SConrad Meyer     if (!r && S_ISFIFO(statbuf.st_mode)) return 1;
138*9cbefe25SConrad Meyer #endif
139*9cbefe25SConrad Meyer     (void)infilename;
140*9cbefe25SConrad Meyer     return 0;
141*9cbefe25SConrad Meyer }
142*9cbefe25SConrad Meyer #endif
143*9cbefe25SConrad Meyer 
144a0483764SConrad Meyer U32 UTIL_isLink(const char* infilename)
145a0483764SConrad Meyer {
146a0483764SConrad Meyer /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
1474d3f1eafSConrad Meyer #if PLATFORM_POSIX_VERSION >= 200112L
148a0483764SConrad Meyer     int r;
149a0483764SConrad Meyer     stat_t statbuf;
150a0483764SConrad Meyer     r = lstat(infilename, &statbuf);
151a0483764SConrad Meyer     if (!r && S_ISLNK(statbuf.st_mode)) return 1;
152a0483764SConrad Meyer #endif
153a0483764SConrad Meyer     (void)infilename;
154a0483764SConrad Meyer     return 0;
155a0483764SConrad Meyer }
156a0483764SConrad Meyer 
157a0483764SConrad Meyer U64 UTIL_getFileSize(const char* infilename)
158a0483764SConrad Meyer {
159a0483764SConrad Meyer     if (!UTIL_isRegularFile(infilename)) return UTIL_FILESIZE_UNKNOWN;
160a0483764SConrad Meyer     {   int r;
161a0483764SConrad Meyer #if defined(_MSC_VER)
162a0483764SConrad Meyer         struct __stat64 statbuf;
163a0483764SConrad Meyer         r = _stat64(infilename, &statbuf);
164a0483764SConrad Meyer         if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
165a0483764SConrad Meyer #elif defined(__MINGW32__) && defined (__MSVCRT__)
166a0483764SConrad Meyer         struct _stati64 statbuf;
167a0483764SConrad Meyer         r = _stati64(infilename, &statbuf);
168a0483764SConrad Meyer         if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
169a0483764SConrad Meyer #else
170a0483764SConrad Meyer         struct stat statbuf;
171a0483764SConrad Meyer         r = stat(infilename, &statbuf);
172a0483764SConrad Meyer         if (r || !S_ISREG(statbuf.st_mode)) return UTIL_FILESIZE_UNKNOWN;
173a0483764SConrad Meyer #endif
174a0483764SConrad Meyer         return (U64)statbuf.st_size;
175a0483764SConrad Meyer     }
176a0483764SConrad Meyer }
177a0483764SConrad Meyer 
178a0483764SConrad Meyer 
179a0483764SConrad Meyer U64 UTIL_getTotalFileSize(const char* const * const fileNamesTable, unsigned nbFiles)
180a0483764SConrad Meyer {
181a0483764SConrad Meyer     U64 total = 0;
182a0483764SConrad Meyer     int error = 0;
183a0483764SConrad Meyer     unsigned n;
184a0483764SConrad Meyer     for (n=0; n<nbFiles; n++) {
185a0483764SConrad Meyer         U64 const size = UTIL_getFileSize(fileNamesTable[n]);
186a0483764SConrad Meyer         error |= (size == UTIL_FILESIZE_UNKNOWN);
187a0483764SConrad Meyer         total += size;
188a0483764SConrad Meyer     }
189a0483764SConrad Meyer     return error ? UTIL_FILESIZE_UNKNOWN : total;
190a0483764SConrad Meyer }
191a0483764SConrad Meyer 
192a0483764SConrad Meyer #ifdef _WIN32
193a0483764SConrad Meyer int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
194a0483764SConrad Meyer {
195a0483764SConrad Meyer     char* path;
196a0483764SConrad Meyer     int dirLength, fnameLength, pathLength, nbFiles = 0;
197a0483764SConrad Meyer     WIN32_FIND_DATAA cFile;
198a0483764SConrad Meyer     HANDLE hFile;
199a0483764SConrad Meyer 
200a0483764SConrad Meyer     dirLength = (int)strlen(dirName);
201a0483764SConrad Meyer     path = (char*) malloc(dirLength + 3);
202a0483764SConrad Meyer     if (!path) return 0;
203a0483764SConrad Meyer 
204a0483764SConrad Meyer     memcpy(path, dirName, dirLength);
205a0483764SConrad Meyer     path[dirLength] = '\\';
206a0483764SConrad Meyer     path[dirLength+1] = '*';
207a0483764SConrad Meyer     path[dirLength+2] = 0;
208a0483764SConrad Meyer 
209a0483764SConrad Meyer     hFile=FindFirstFileA(path, &cFile);
210a0483764SConrad Meyer     if (hFile == INVALID_HANDLE_VALUE) {
211a0483764SConrad Meyer         UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName);
212a0483764SConrad Meyer         return 0;
213a0483764SConrad Meyer     }
214a0483764SConrad Meyer     free(path);
215a0483764SConrad Meyer 
216a0483764SConrad Meyer     do {
217a0483764SConrad Meyer         fnameLength = (int)strlen(cFile.cFileName);
218a0483764SConrad Meyer         path = (char*) malloc(dirLength + fnameLength + 2);
219a0483764SConrad Meyer         if (!path) { FindClose(hFile); return 0; }
220a0483764SConrad Meyer         memcpy(path, dirName, dirLength);
221a0483764SConrad Meyer         path[dirLength] = '\\';
222a0483764SConrad Meyer         memcpy(path+dirLength+1, cFile.cFileName, fnameLength);
223a0483764SConrad Meyer         pathLength = dirLength+1+fnameLength;
224a0483764SConrad Meyer         path[pathLength] = 0;
225a0483764SConrad Meyer         if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
226a0483764SConrad Meyer             if ( strcmp (cFile.cFileName, "..") == 0
227a0483764SConrad Meyer               || strcmp (cFile.cFileName, ".") == 0 )
228a0483764SConrad Meyer                 continue;
229a0483764SConrad Meyer             /* Recursively call "UTIL_prepareFileList" with the new path. */
230a0483764SConrad Meyer             nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks);
231a0483764SConrad Meyer             if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
232a0483764SConrad Meyer         } else if ( (cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
233a0483764SConrad Meyer                  || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
234a0483764SConrad Meyer                  || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) {
235a0483764SConrad Meyer             if (*bufStart + *pos + pathLength >= *bufEnd) {
236a0483764SConrad Meyer                 ptrdiff_t const newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
237a0483764SConrad Meyer                 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
238a0483764SConrad Meyer                 if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
239a0483764SConrad Meyer                 *bufEnd = *bufStart + newListSize;
240a0483764SConrad Meyer             }
241a0483764SConrad Meyer             if (*bufStart + *pos + pathLength < *bufEnd) {
242a0483764SConrad Meyer                 memcpy(*bufStart + *pos, path, pathLength+1 /* include final \0 */);
243a0483764SConrad Meyer                 *pos += pathLength + 1;
244a0483764SConrad Meyer                 nbFiles++;
245a0483764SConrad Meyer             }
246a0483764SConrad Meyer         }
247a0483764SConrad Meyer         free(path);
248a0483764SConrad Meyer     } while (FindNextFileA(hFile, &cFile));
249a0483764SConrad Meyer 
250a0483764SConrad Meyer     FindClose(hFile);
251a0483764SConrad Meyer     return nbFiles;
252a0483764SConrad Meyer }
253a0483764SConrad Meyer 
254a0483764SConrad Meyer #elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L)  /* opendir, readdir require POSIX.1-2001 */
255a0483764SConrad Meyer 
256a0483764SConrad Meyer int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
257a0483764SConrad Meyer {
258a0483764SConrad Meyer     DIR *dir;
259a0483764SConrad Meyer     struct dirent *entry;
260a0483764SConrad Meyer     char* path;
261*9cbefe25SConrad Meyer     size_t dirLength, fnameLength, pathLength;
262*9cbefe25SConrad Meyer     int nbFiles = 0;
263a0483764SConrad Meyer 
264a0483764SConrad Meyer     if (!(dir = opendir(dirName))) {
265a0483764SConrad Meyer         UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
266a0483764SConrad Meyer         return 0;
267a0483764SConrad Meyer     }
268a0483764SConrad Meyer 
269*9cbefe25SConrad Meyer     dirLength = strlen(dirName);
270a0483764SConrad Meyer     errno = 0;
271a0483764SConrad Meyer     while ((entry = readdir(dir)) != NULL) {
272a0483764SConrad Meyer         if (strcmp (entry->d_name, "..") == 0 ||
273a0483764SConrad Meyer             strcmp (entry->d_name, ".") == 0) continue;
274*9cbefe25SConrad Meyer         fnameLength = strlen(entry->d_name);
275a0483764SConrad Meyer         path = (char*) malloc(dirLength + fnameLength + 2);
276a0483764SConrad Meyer         if (!path) { closedir(dir); return 0; }
277a0483764SConrad Meyer         memcpy(path, dirName, dirLength);
278a0483764SConrad Meyer 
279a0483764SConrad Meyer         path[dirLength] = '/';
280a0483764SConrad Meyer         memcpy(path+dirLength+1, entry->d_name, fnameLength);
281a0483764SConrad Meyer         pathLength = dirLength+1+fnameLength;
282a0483764SConrad Meyer         path[pathLength] = 0;
283a0483764SConrad Meyer 
284a0483764SConrad Meyer         if (!followLinks && UTIL_isLink(path)) {
285a0483764SConrad Meyer             UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path);
2864d3f1eafSConrad Meyer             free(path);
287a0483764SConrad Meyer             continue;
288a0483764SConrad Meyer         }
289a0483764SConrad Meyer 
290a0483764SConrad Meyer         if (UTIL_isDirectory(path)) {
291a0483764SConrad Meyer             nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks);  /* Recursively call "UTIL_prepareFileList" with the new path. */
292a0483764SConrad Meyer             if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
293a0483764SConrad Meyer         } else {
294a0483764SConrad Meyer             if (*bufStart + *pos + pathLength >= *bufEnd) {
295a0483764SConrad Meyer                 ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
296*9cbefe25SConrad Meyer                 assert(newListSize >= 0);
297*9cbefe25SConrad Meyer                 *bufStart = (char*)UTIL_realloc(*bufStart, (size_t)newListSize);
298a0483764SConrad Meyer                 *bufEnd = *bufStart + newListSize;
299a0483764SConrad Meyer                 if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
300a0483764SConrad Meyer             }
301a0483764SConrad Meyer             if (*bufStart + *pos + pathLength < *bufEnd) {
302a0483764SConrad Meyer                 memcpy(*bufStart + *pos, path, pathLength + 1);  /* with final \0 */
303a0483764SConrad Meyer                 *pos += pathLength + 1;
304a0483764SConrad Meyer                 nbFiles++;
305a0483764SConrad Meyer             }
306a0483764SConrad Meyer         }
307a0483764SConrad Meyer         free(path);
308a0483764SConrad Meyer         errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */
309a0483764SConrad Meyer     }
310a0483764SConrad Meyer 
311a0483764SConrad Meyer     if (errno != 0) {
312a0483764SConrad Meyer         UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s\n", dirName, strerror(errno));
313a0483764SConrad Meyer         free(*bufStart);
314a0483764SConrad Meyer         *bufStart = NULL;
315a0483764SConrad Meyer     }
316a0483764SConrad Meyer     closedir(dir);
317a0483764SConrad Meyer     return nbFiles;
318a0483764SConrad Meyer }
319a0483764SConrad Meyer 
320a0483764SConrad Meyer #else
321a0483764SConrad Meyer 
322a0483764SConrad Meyer int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
323a0483764SConrad Meyer {
324a0483764SConrad Meyer     (void)bufStart; (void)bufEnd; (void)pos; (void)followLinks;
325a0483764SConrad Meyer     UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
326a0483764SConrad Meyer     return 0;
327a0483764SConrad Meyer }
328a0483764SConrad Meyer 
329a0483764SConrad Meyer #endif /* #ifdef _WIN32 */
330a0483764SConrad Meyer 
331*9cbefe25SConrad Meyer int UTIL_isCompressedFile(const char *inputName, const char *extensionList[])
332*9cbefe25SConrad Meyer {
333*9cbefe25SConrad Meyer   const char* ext = UTIL_getFileExtension(inputName);
334*9cbefe25SConrad Meyer   while(*extensionList!=NULL)
335*9cbefe25SConrad Meyer   {
336*9cbefe25SConrad Meyer     const int isCompressedExtension = strcmp(ext,*extensionList);
337*9cbefe25SConrad Meyer     if(isCompressedExtension==0)
338*9cbefe25SConrad Meyer       return 1;
339*9cbefe25SConrad Meyer     ++extensionList;
340*9cbefe25SConrad Meyer   }
341*9cbefe25SConrad Meyer    return 0;
342*9cbefe25SConrad Meyer }
343*9cbefe25SConrad Meyer 
344*9cbefe25SConrad Meyer /*Utility function to get file extension from file */
345*9cbefe25SConrad Meyer const char* UTIL_getFileExtension(const char* infilename)
346*9cbefe25SConrad Meyer {
347*9cbefe25SConrad Meyer    const char* extension = strrchr(infilename, '.');
348*9cbefe25SConrad Meyer    if(!extension || extension==infilename) return "";
349*9cbefe25SConrad Meyer    return extension;
350*9cbefe25SConrad Meyer }
351*9cbefe25SConrad Meyer 
352a0483764SConrad Meyer /*
353a0483764SConrad Meyer  * UTIL_createFileList - takes a list of files and directories (params: inputNames, inputNamesNb), scans directories,
354a0483764SConrad Meyer  *                       and returns a new list of files (params: return value, allocatedBuffer, allocatedNamesNb).
355a0483764SConrad Meyer  * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer)
356a0483764SConrad Meyer  * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called.
357a0483764SConrad Meyer  */
358a0483764SConrad Meyer const char**
359a0483764SConrad Meyer UTIL_createFileList(const char **inputNames, unsigned inputNamesNb,
360a0483764SConrad Meyer                     char** allocatedBuffer, unsigned* allocatedNamesNb,
361a0483764SConrad Meyer                     int followLinks)
362a0483764SConrad Meyer {
363a0483764SConrad Meyer     size_t pos;
364a0483764SConrad Meyer     unsigned i, nbFiles;
365a0483764SConrad Meyer     char* buf = (char*)malloc(LIST_SIZE_INCREASE);
366a0483764SConrad Meyer     char* bufend = buf + LIST_SIZE_INCREASE;
367a0483764SConrad Meyer 
368a0483764SConrad Meyer     if (!buf) return NULL;
369a0483764SConrad Meyer 
370a0483764SConrad Meyer     for (i=0, pos=0, nbFiles=0; i<inputNamesNb; i++) {
371a0483764SConrad Meyer         if (!UTIL_isDirectory(inputNames[i])) {
372a0483764SConrad Meyer             size_t const len = strlen(inputNames[i]);
373a0483764SConrad Meyer             if (buf + pos + len >= bufend) {
374a0483764SConrad Meyer                 ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE;
375*9cbefe25SConrad Meyer                 assert(newListSize >= 0);
376*9cbefe25SConrad Meyer                 buf = (char*)UTIL_realloc(buf, (size_t)newListSize);
377a0483764SConrad Meyer                 bufend = buf + newListSize;
378a0483764SConrad Meyer                 if (!buf) return NULL;
379a0483764SConrad Meyer             }
380a0483764SConrad Meyer             if (buf + pos + len < bufend) {
381*9cbefe25SConrad Meyer                 memcpy(buf+pos, inputNames[i], len+1);  /* including final \0 */
382a0483764SConrad Meyer                 pos += len + 1;
383a0483764SConrad Meyer                 nbFiles++;
384a0483764SConrad Meyer             }
385a0483764SConrad Meyer         } else {
386*9cbefe25SConrad Meyer             nbFiles += (unsigned)UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend, followLinks);
387a0483764SConrad Meyer             if (buf == NULL) return NULL;
388a0483764SConrad Meyer     }   }
389a0483764SConrad Meyer 
390a0483764SConrad Meyer     if (nbFiles == 0) { free(buf); return NULL; }
391a0483764SConrad Meyer 
392*9cbefe25SConrad Meyer     {   const char** const fileTable = (const char**)malloc((nbFiles + 1) * sizeof(*fileTable));
393a0483764SConrad Meyer         if (!fileTable) { free(buf); return NULL; }
394a0483764SConrad Meyer 
395a0483764SConrad Meyer         for (i = 0, pos = 0; i < nbFiles; i++) {
396a0483764SConrad Meyer             fileTable[i] = buf + pos;
397*9cbefe25SConrad Meyer             if (buf + pos > bufend) { free(buf); free((void*)fileTable); return NULL; }
398a0483764SConrad Meyer             pos += strlen(fileTable[i]) + 1;
399a0483764SConrad Meyer         }
400a0483764SConrad Meyer 
401a0483764SConrad Meyer         *allocatedBuffer = buf;
402a0483764SConrad Meyer         *allocatedNamesNb = nbFiles;
403a0483764SConrad Meyer 
404a0483764SConrad Meyer         return fileTable;
405a0483764SConrad Meyer     }
406*9cbefe25SConrad Meyer }
407a0483764SConrad Meyer 
4082b9c00cbSConrad Meyer 
409a0483764SConrad Meyer /*-****************************************
410a0483764SConrad Meyer *  Console log
411a0483764SConrad Meyer ******************************************/
412a0483764SConrad Meyer int g_utilDisplayLevel;
413a0483764SConrad Meyer 
414a0483764SConrad Meyer 
4152b9c00cbSConrad Meyer 
416a0483764SConrad Meyer /*-****************************************
4172b9c00cbSConrad Meyer *  count the number of physical cores
418a0483764SConrad Meyer ******************************************/
419a0483764SConrad Meyer 
420a0483764SConrad Meyer #if defined(_WIN32) || defined(WIN32)
421a0483764SConrad Meyer 
422a0483764SConrad Meyer #include <windows.h>
423a0483764SConrad Meyer 
424a0483764SConrad Meyer typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
425a0483764SConrad Meyer 
426a0483764SConrad Meyer int UTIL_countPhysicalCores(void)
427a0483764SConrad Meyer {
428a0483764SConrad Meyer     static int numPhysicalCores = 0;
429a0483764SConrad Meyer     if (numPhysicalCores != 0) return numPhysicalCores;
430a0483764SConrad Meyer 
431a0483764SConrad Meyer     {   LPFN_GLPI glpi;
432a0483764SConrad Meyer         BOOL done = FALSE;
433a0483764SConrad Meyer         PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
434a0483764SConrad Meyer         PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
435a0483764SConrad Meyer         DWORD returnLength = 0;
436a0483764SConrad Meyer         size_t byteOffset = 0;
437a0483764SConrad Meyer 
438*9cbefe25SConrad Meyer #if defined(_MSC_VER)
439*9cbefe25SConrad Meyer /* Visual Studio does not like the following cast */
440*9cbefe25SConrad Meyer #   pragma warning( disable : 4054 )  /* conversion from function ptr to data ptr */
441*9cbefe25SConrad Meyer #   pragma warning( disable : 4055 )  /* conversion from data ptr to function ptr */
442*9cbefe25SConrad Meyer #endif
443*9cbefe25SConrad Meyer         glpi = (LPFN_GLPI)(void*)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
444a0483764SConrad Meyer                                                "GetLogicalProcessorInformation");
445a0483764SConrad Meyer 
446a0483764SConrad Meyer         if (glpi == NULL) {
447a0483764SConrad Meyer             goto failed;
448a0483764SConrad Meyer         }
449a0483764SConrad Meyer 
450a0483764SConrad Meyer         while(!done) {
451a0483764SConrad Meyer             DWORD rc = glpi(buffer, &returnLength);
452a0483764SConrad Meyer             if (FALSE == rc) {
453a0483764SConrad Meyer                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
454a0483764SConrad Meyer                     if (buffer)
455a0483764SConrad Meyer                         free(buffer);
456a0483764SConrad Meyer                     buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
457a0483764SConrad Meyer 
458a0483764SConrad Meyer                     if (buffer == NULL) {
459a0483764SConrad Meyer                         perror("zstd");
460a0483764SConrad Meyer                         exit(1);
461a0483764SConrad Meyer                     }
462a0483764SConrad Meyer                 } else {
463a0483764SConrad Meyer                     /* some other error */
464a0483764SConrad Meyer                     goto failed;
465a0483764SConrad Meyer                 }
466a0483764SConrad Meyer             } else {
467a0483764SConrad Meyer                 done = TRUE;
468a0483764SConrad Meyer             }
469a0483764SConrad Meyer         }
470a0483764SConrad Meyer 
471a0483764SConrad Meyer         ptr = buffer;
472a0483764SConrad Meyer 
473a0483764SConrad Meyer         while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
474a0483764SConrad Meyer 
475a0483764SConrad Meyer             if (ptr->Relationship == RelationProcessorCore) {
476a0483764SConrad Meyer                 numPhysicalCores++;
477a0483764SConrad Meyer             }
478a0483764SConrad Meyer 
479a0483764SConrad Meyer             ptr++;
480a0483764SConrad Meyer             byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
481a0483764SConrad Meyer         }
482a0483764SConrad Meyer 
483a0483764SConrad Meyer         free(buffer);
484a0483764SConrad Meyer 
485a0483764SConrad Meyer         return numPhysicalCores;
486a0483764SConrad Meyer     }
487a0483764SConrad Meyer 
488a0483764SConrad Meyer failed:
489a0483764SConrad Meyer     /* try to fall back on GetSystemInfo */
490a0483764SConrad Meyer     {   SYSTEM_INFO sysinfo;
491a0483764SConrad Meyer         GetSystemInfo(&sysinfo);
492a0483764SConrad Meyer         numPhysicalCores = sysinfo.dwNumberOfProcessors;
493a0483764SConrad Meyer         if (numPhysicalCores == 0) numPhysicalCores = 1; /* just in case */
494a0483764SConrad Meyer     }
495a0483764SConrad Meyer     return numPhysicalCores;
496a0483764SConrad Meyer }
497a0483764SConrad Meyer 
498a0483764SConrad Meyer #elif defined(__APPLE__)
499a0483764SConrad Meyer 
500a0483764SConrad Meyer #include <sys/sysctl.h>
501a0483764SConrad Meyer 
502a0483764SConrad Meyer /* Use apple-provided syscall
503a0483764SConrad Meyer  * see: man 3 sysctl */
504a0483764SConrad Meyer int UTIL_countPhysicalCores(void)
505a0483764SConrad Meyer {
506a0483764SConrad Meyer     static S32 numPhysicalCores = 0; /* apple specifies int32_t */
507a0483764SConrad Meyer     if (numPhysicalCores != 0) return numPhysicalCores;
508a0483764SConrad Meyer 
509a0483764SConrad Meyer     {   size_t size = sizeof(S32);
510a0483764SConrad Meyer         int const ret = sysctlbyname("hw.physicalcpu", &numPhysicalCores, &size, NULL, 0);
511a0483764SConrad Meyer         if (ret != 0) {
512a0483764SConrad Meyer             if (errno == ENOENT) {
513a0483764SConrad Meyer                 /* entry not present, fall back on 1 */
514a0483764SConrad Meyer                 numPhysicalCores = 1;
515a0483764SConrad Meyer             } else {
516a0483764SConrad Meyer                 perror("zstd: can't get number of physical cpus");
517a0483764SConrad Meyer                 exit(1);
518a0483764SConrad Meyer             }
519a0483764SConrad Meyer         }
520a0483764SConrad Meyer 
521a0483764SConrad Meyer         return numPhysicalCores;
522a0483764SConrad Meyer     }
523a0483764SConrad Meyer }
524a0483764SConrad Meyer 
525a0483764SConrad Meyer #elif defined(__linux__)
526a0483764SConrad Meyer 
527a0483764SConrad Meyer /* parse /proc/cpuinfo
528a0483764SConrad Meyer  * siblings / cpu cores should give hyperthreading ratio
529a0483764SConrad Meyer  * otherwise fall back on sysconf */
530a0483764SConrad Meyer int UTIL_countPhysicalCores(void)
531a0483764SConrad Meyer {
532a0483764SConrad Meyer     static int numPhysicalCores = 0;
533a0483764SConrad Meyer 
534a0483764SConrad Meyer     if (numPhysicalCores != 0) return numPhysicalCores;
535a0483764SConrad Meyer 
536a0483764SConrad Meyer     numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
537a0483764SConrad Meyer     if (numPhysicalCores == -1) {
538a0483764SConrad Meyer         /* value not queryable, fall back on 1 */
539a0483764SConrad Meyer         return numPhysicalCores = 1;
540a0483764SConrad Meyer     }
541a0483764SConrad Meyer 
542a0483764SConrad Meyer     /* try to determine if there's hyperthreading */
543a0483764SConrad Meyer     {   FILE* const cpuinfo = fopen("/proc/cpuinfo", "r");
544a0483764SConrad Meyer #define BUF_SIZE 80
545a0483764SConrad Meyer         char buff[BUF_SIZE];
546a0483764SConrad Meyer 
547a0483764SConrad Meyer         int siblings = 0;
548a0483764SConrad Meyer         int cpu_cores = 0;
549a0483764SConrad Meyer         int ratio = 1;
550a0483764SConrad Meyer 
551a0483764SConrad Meyer         if (cpuinfo == NULL) {
552a0483764SConrad Meyer             /* fall back on the sysconf value */
553a0483764SConrad Meyer             return numPhysicalCores;
554a0483764SConrad Meyer         }
555a0483764SConrad Meyer 
556a0483764SConrad Meyer         /* assume the cpu cores/siblings values will be constant across all
557a0483764SConrad Meyer          * present processors */
558a0483764SConrad Meyer         while (!feof(cpuinfo)) {
559a0483764SConrad Meyer             if (fgets(buff, BUF_SIZE, cpuinfo) != NULL) {
560a0483764SConrad Meyer                 if (strncmp(buff, "siblings", 8) == 0) {
561a0483764SConrad Meyer                     const char* const sep = strchr(buff, ':');
562*9cbefe25SConrad Meyer                     if (sep == NULL || *sep == '\0') {
563a0483764SConrad Meyer                         /* formatting was broken? */
564a0483764SConrad Meyer                         goto failed;
565a0483764SConrad Meyer                     }
566a0483764SConrad Meyer 
567a0483764SConrad Meyer                     siblings = atoi(sep + 1);
568a0483764SConrad Meyer                 }
569a0483764SConrad Meyer                 if (strncmp(buff, "cpu cores", 9) == 0) {
570a0483764SConrad Meyer                     const char* const sep = strchr(buff, ':');
571*9cbefe25SConrad Meyer                     if (sep == NULL || *sep == '\0') {
572a0483764SConrad Meyer                         /* formatting was broken? */
573a0483764SConrad Meyer                         goto failed;
574a0483764SConrad Meyer                     }
575a0483764SConrad Meyer 
576a0483764SConrad Meyer                     cpu_cores = atoi(sep + 1);
577a0483764SConrad Meyer                 }
578a0483764SConrad Meyer             } else if (ferror(cpuinfo)) {
579a0483764SConrad Meyer                 /* fall back on the sysconf value */
580a0483764SConrad Meyer                 goto failed;
581a0483764SConrad Meyer             }
582a0483764SConrad Meyer         }
583a0483764SConrad Meyer         if (siblings && cpu_cores) {
584a0483764SConrad Meyer             ratio = siblings / cpu_cores;
585a0483764SConrad Meyer         }
586a0483764SConrad Meyer failed:
587a0483764SConrad Meyer         fclose(cpuinfo);
588a0483764SConrad Meyer         return numPhysicalCores = numPhysicalCores / ratio;
589a0483764SConrad Meyer     }
590a0483764SConrad Meyer }
591a0483764SConrad Meyer 
5922b9c00cbSConrad Meyer #elif defined(__FreeBSD__)
593a0483764SConrad Meyer 
5942b9c00cbSConrad Meyer #include <sys/param.h>
5952b9c00cbSConrad Meyer #include <sys/sysctl.h>
5962b9c00cbSConrad Meyer 
5972b9c00cbSConrad Meyer /* Use physical core sysctl when available
5982b9c00cbSConrad Meyer  * see: man 4 smp, man 3 sysctl */
5992b9c00cbSConrad Meyer int UTIL_countPhysicalCores(void)
6002b9c00cbSConrad Meyer {
6012b9c00cbSConrad Meyer     static int numPhysicalCores = 0; /* freebsd sysctl is native int sized */
6022b9c00cbSConrad Meyer     if (numPhysicalCores != 0) return numPhysicalCores;
6032b9c00cbSConrad Meyer 
6042b9c00cbSConrad Meyer #if __FreeBSD_version >= 1300008
6052b9c00cbSConrad Meyer     {   size_t size = sizeof(numPhysicalCores);
6062b9c00cbSConrad Meyer         int ret = sysctlbyname("kern.smp.cores", &numPhysicalCores, &size, NULL, 0);
6072b9c00cbSConrad Meyer         if (ret == 0) return numPhysicalCores;
6082b9c00cbSConrad Meyer         if (errno != ENOENT) {
6092b9c00cbSConrad Meyer             perror("zstd: can't get number of physical cpus");
6102b9c00cbSConrad Meyer             exit(1);
6112b9c00cbSConrad Meyer         }
6122b9c00cbSConrad Meyer         /* sysctl not present, fall through to older sysconf method */
6132b9c00cbSConrad Meyer     }
6142b9c00cbSConrad Meyer #endif
6152b9c00cbSConrad Meyer 
6162b9c00cbSConrad Meyer     numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
6172b9c00cbSConrad Meyer     if (numPhysicalCores == -1) {
6182b9c00cbSConrad Meyer         /* value not queryable, fall back on 1 */
6192b9c00cbSConrad Meyer         numPhysicalCores = 1;
6202b9c00cbSConrad Meyer     }
6212b9c00cbSConrad Meyer     return numPhysicalCores;
6222b9c00cbSConrad Meyer }
6232b9c00cbSConrad Meyer 
6242b9c00cbSConrad Meyer #elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
6252b9c00cbSConrad Meyer 
6262b9c00cbSConrad Meyer /* Use POSIX sysconf
6272b9c00cbSConrad Meyer  * see: man 3 sysconf */
628a0483764SConrad Meyer int UTIL_countPhysicalCores(void)
629a0483764SConrad Meyer {
630a0483764SConrad Meyer     static int numPhysicalCores = 0;
631a0483764SConrad Meyer 
632a0483764SConrad Meyer     if (numPhysicalCores != 0) return numPhysicalCores;
633a0483764SConrad Meyer 
634a0483764SConrad Meyer     numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
635a0483764SConrad Meyer     if (numPhysicalCores == -1) {
636a0483764SConrad Meyer         /* value not queryable, fall back on 1 */
637a0483764SConrad Meyer         return numPhysicalCores = 1;
638a0483764SConrad Meyer     }
639a0483764SConrad Meyer     return numPhysicalCores;
640a0483764SConrad Meyer }
641a0483764SConrad Meyer 
642a0483764SConrad Meyer #else
643a0483764SConrad Meyer 
644a0483764SConrad Meyer int UTIL_countPhysicalCores(void)
645a0483764SConrad Meyer {
646a0483764SConrad Meyer     /* assume 1 */
647a0483764SConrad Meyer     return 1;
648a0483764SConrad Meyer }
649a0483764SConrad Meyer 
650a0483764SConrad Meyer #endif
651a0483764SConrad Meyer 
652a0483764SConrad Meyer #if defined (__cplusplus)
653a0483764SConrad Meyer }
654a0483764SConrad Meyer #endif
655