util.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. /*
  2. * Copyright (c) Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under both the BSD-style license (found in the
  6. * LICENSE file in the root directory of this source tree) and the GPLv2 (found
  7. * in the COPYING file in the root directory of this source tree).
  8. * You may select, at your option, one of the above-listed licenses.
  9. */
  10. #if defined (__cplusplus)
  11. extern "C" {
  12. #endif
  13. /*-****************************************
  14. * Dependencies
  15. ******************************************/
  16. #include "util.h" /* note : ensure that platform.h is included first ! */
  17. #include <stdlib.h> /* malloc, realloc, free */
  18. #include <stdio.h> /* fprintf */
  19. #include <time.h> /* clock_t, clock, CLOCKS_PER_SEC, nanosleep */
  20. #include <errno.h>
  21. #include <assert.h>
  22. #if defined(_WIN32)
  23. # include <sys/utime.h> /* utime */
  24. # include <io.h> /* _chmod */
  25. #else
  26. # include <unistd.h> /* chown, stat */
  27. # if PLATFORM_POSIX_VERSION < 200809L || !defined(st_mtime)
  28. # include <utime.h> /* utime */
  29. # else
  30. # include <fcntl.h> /* AT_FDCWD */
  31. # include <sys/stat.h> /* utimensat */
  32. # endif
  33. #endif
  34. #if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
  35. #include <direct.h> /* needed for _mkdir in windows */
  36. #endif
  37. #if defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */
  38. # include <dirent.h> /* opendir, readdir */
  39. # include <string.h> /* strerror, memcpy */
  40. #endif /* #ifdef _WIN32 */
  41. /*-****************************************
  42. * Internal Macros
  43. ******************************************/
  44. /* CONTROL is almost like an assert(), but is never disabled.
  45. * It's designed for failures that may happen rarely,
  46. * but we don't want to maintain a specific error code path for them,
  47. * such as a malloc() returning NULL for example.
  48. * Since it's always active, this macro can trigger side effects.
  49. */
  50. #define CONTROL(c) { \
  51. if (!(c)) { \
  52. UTIL_DISPLAYLEVEL(1, "Error : %s, %i : %s", \
  53. __FILE__, __LINE__, #c); \
  54. exit(1); \
  55. } }
  56. /* console log */
  57. #define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__)
  58. #define UTIL_DISPLAYLEVEL(l, ...) { if (g_utilDisplayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
  59. /* A modified version of realloc().
  60. * If UTIL_realloc() fails the original block is freed.
  61. */
  62. UTIL_STATIC void* UTIL_realloc(void *ptr, size_t size)
  63. {
  64. void *newptr = realloc(ptr, size);
  65. if (newptr) return newptr;
  66. free(ptr);
  67. return NULL;
  68. }
  69. #if defined(_MSC_VER)
  70. #define chmod _chmod
  71. #endif
  72. /*-****************************************
  73. * Console log
  74. ******************************************/
  75. int g_utilDisplayLevel;
  76. int UTIL_requireUserConfirmation(const char* prompt, const char* abortMsg,
  77. const char* acceptableLetters, int hasStdinInput) {
  78. int ch, result;
  79. if (hasStdinInput) {
  80. UTIL_DISPLAY("stdin is an input - not proceeding.\n");
  81. return 1;
  82. }
  83. UTIL_DISPLAY("%s", prompt);
  84. ch = getchar();
  85. result = 0;
  86. if (strchr(acceptableLetters, ch) == NULL) {
  87. UTIL_DISPLAY("%s", abortMsg);
  88. result = 1;
  89. }
  90. /* flush the rest */
  91. while ((ch!=EOF) && (ch!='\n'))
  92. ch = getchar();
  93. return result;
  94. }
  95. /*-*************************************
  96. * Constants
  97. ***************************************/
  98. #define LIST_SIZE_INCREASE (8*1024)
  99. #define MAX_FILE_OF_FILE_NAMES_SIZE (1<<20)*50
  100. /*-*************************************
  101. * Functions
  102. ***************************************/
  103. int UTIL_stat(const char* filename, stat_t* statbuf)
  104. {
  105. #if defined(_MSC_VER)
  106. return !_stat64(filename, statbuf);
  107. #elif defined(__MINGW32__) && defined (__MSVCRT__)
  108. return !_stati64(filename, statbuf);
  109. #else
  110. return !stat(filename, statbuf);
  111. #endif
  112. }
  113. int UTIL_isRegularFile(const char* infilename)
  114. {
  115. stat_t statbuf;
  116. return UTIL_stat(infilename, &statbuf) && UTIL_isRegularFileStat(&statbuf);
  117. }
  118. int UTIL_isRegularFileStat(const stat_t* statbuf)
  119. {
  120. #if defined(_MSC_VER)
  121. return (statbuf->st_mode & S_IFREG) != 0;
  122. #else
  123. return S_ISREG(statbuf->st_mode) != 0;
  124. #endif
  125. }
  126. /* like chmod, but avoid changing permission of /dev/null */
  127. int UTIL_chmod(char const* filename, const stat_t* statbuf, mode_t permissions)
  128. {
  129. stat_t localStatBuf;
  130. if (statbuf == NULL) {
  131. if (!UTIL_stat(filename, &localStatBuf)) return 0;
  132. statbuf = &localStatBuf;
  133. }
  134. if (!UTIL_isRegularFileStat(statbuf)) return 0; /* pretend success, but don't change anything */
  135. return chmod(filename, permissions);
  136. }
  137. /* set access and modification times */
  138. int UTIL_utime(const char* filename, const stat_t *statbuf)
  139. {
  140. int ret;
  141. /* We check that st_mtime is a macro here in order to give us confidence
  142. * that struct stat has a struct timespec st_mtim member. We need this
  143. * check because there are some platforms that claim to be POSIX 2008
  144. * compliant but which do not have st_mtim... */
  145. #if (PLATFORM_POSIX_VERSION >= 200809L) && defined(st_mtime)
  146. /* (atime, mtime) */
  147. struct timespec timebuf[2] = { {0, UTIME_NOW} };
  148. timebuf[1] = statbuf->st_mtim;
  149. ret = utimensat(AT_FDCWD, filename, timebuf, 0);
  150. #else
  151. struct utimbuf timebuf;
  152. timebuf.actime = time(NULL);
  153. timebuf.modtime = statbuf->st_mtime;
  154. ret = utime(filename, &timebuf);
  155. #endif
  156. errno = 0;
  157. return ret;
  158. }
  159. int UTIL_setFileStat(const char *filename, const stat_t *statbuf)
  160. {
  161. int res = 0;
  162. stat_t curStatBuf;
  163. if (!UTIL_stat(filename, &curStatBuf) || !UTIL_isRegularFileStat(&curStatBuf))
  164. return -1;
  165. /* set access and modification times */
  166. res += UTIL_utime(filename, statbuf);
  167. #if !defined(_WIN32)
  168. res += chown(filename, statbuf->st_uid, statbuf->st_gid); /* Copy ownership */
  169. #endif
  170. res += UTIL_chmod(filename, &curStatBuf, statbuf->st_mode & 07777); /* Copy file permissions */
  171. errno = 0;
  172. return -res; /* number of errors is returned */
  173. }
  174. int UTIL_isDirectory(const char* infilename)
  175. {
  176. stat_t statbuf;
  177. return UTIL_stat(infilename, &statbuf) && UTIL_isDirectoryStat(&statbuf);
  178. }
  179. int UTIL_isDirectoryStat(const stat_t* statbuf)
  180. {
  181. #if defined(_MSC_VER)
  182. return (statbuf->st_mode & _S_IFDIR) != 0;
  183. #else
  184. return S_ISDIR(statbuf->st_mode) != 0;
  185. #endif
  186. }
  187. int UTIL_compareStr(const void *p1, const void *p2) {
  188. return strcmp(* (char * const *) p1, * (char * const *) p2);
  189. }
  190. int UTIL_isSameFile(const char* fName1, const char* fName2)
  191. {
  192. assert(fName1 != NULL); assert(fName2 != NULL);
  193. #if defined(_MSC_VER) || defined(_WIN32)
  194. /* note : Visual does not support file identification by inode.
  195. * inode does not work on Windows, even with a posix layer, like msys2.
  196. * The following work-around is limited to detecting exact name repetition only,
  197. * aka `filename` is considered different from `subdir/../filename` */
  198. return !strcmp(fName1, fName2);
  199. #else
  200. { stat_t file1Stat;
  201. stat_t file2Stat;
  202. return UTIL_stat(fName1, &file1Stat)
  203. && UTIL_stat(fName2, &file2Stat)
  204. && (file1Stat.st_dev == file2Stat.st_dev)
  205. && (file1Stat.st_ino == file2Stat.st_ino);
  206. }
  207. #endif
  208. }
  209. /* UTIL_isFIFO : distinguish named pipes */
  210. int UTIL_isFIFO(const char* infilename)
  211. {
  212. /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
  213. #if PLATFORM_POSIX_VERSION >= 200112L
  214. stat_t statbuf;
  215. if (UTIL_stat(infilename, &statbuf) && UTIL_isFIFOStat(&statbuf)) return 1;
  216. #endif
  217. (void)infilename;
  218. return 0;
  219. }
  220. /* UTIL_isFIFO : distinguish named pipes */
  221. int UTIL_isFIFOStat(const stat_t* statbuf)
  222. {
  223. /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
  224. #if PLATFORM_POSIX_VERSION >= 200112L
  225. if (S_ISFIFO(statbuf->st_mode)) return 1;
  226. #endif
  227. (void)statbuf;
  228. return 0;
  229. }
  230. /* UTIL_isBlockDevStat : distinguish named pipes */
  231. int UTIL_isBlockDevStat(const stat_t* statbuf)
  232. {
  233. /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
  234. #if PLATFORM_POSIX_VERSION >= 200112L
  235. if (S_ISBLK(statbuf->st_mode)) return 1;
  236. #endif
  237. (void)statbuf;
  238. return 0;
  239. }
  240. int UTIL_isLink(const char* infilename)
  241. {
  242. /* macro guards, as defined in : https://linux.die.net/man/2/lstat */
  243. #if PLATFORM_POSIX_VERSION >= 200112L
  244. stat_t statbuf;
  245. int const r = lstat(infilename, &statbuf);
  246. if (!r && S_ISLNK(statbuf.st_mode)) return 1;
  247. #endif
  248. (void)infilename;
  249. return 0;
  250. }
  251. U64 UTIL_getFileSize(const char* infilename)
  252. {
  253. stat_t statbuf;
  254. if (!UTIL_stat(infilename, &statbuf)) return UTIL_FILESIZE_UNKNOWN;
  255. return UTIL_getFileSizeStat(&statbuf);
  256. }
  257. U64 UTIL_getFileSizeStat(const stat_t* statbuf)
  258. {
  259. if (!UTIL_isRegularFileStat(statbuf)) return UTIL_FILESIZE_UNKNOWN;
  260. #if defined(_MSC_VER)
  261. if (!(statbuf->st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
  262. #elif defined(__MINGW32__) && defined (__MSVCRT__)
  263. if (!(statbuf->st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN;
  264. #else
  265. if (!S_ISREG(statbuf->st_mode)) return UTIL_FILESIZE_UNKNOWN;
  266. #endif
  267. return (U64)statbuf->st_size;
  268. }
  269. UTIL_HumanReadableSize_t UTIL_makeHumanReadableSize(U64 size)
  270. {
  271. UTIL_HumanReadableSize_t hrs;
  272. if (g_utilDisplayLevel > 3) {
  273. /* In verbose mode, do not scale sizes down, except in the case of
  274. * values that exceed the integral precision of a double. */
  275. if (size >= (1ull << 53)) {
  276. hrs.value = (double)size / (1ull << 20);
  277. hrs.suffix = " MiB";
  278. /* At worst, a double representation of a maximal size will be
  279. * accurate to better than tens of kilobytes. */
  280. hrs.precision = 2;
  281. } else {
  282. hrs.value = (double)size;
  283. hrs.suffix = " B";
  284. hrs.precision = 0;
  285. }
  286. } else {
  287. /* In regular mode, scale sizes down and use suffixes. */
  288. if (size >= (1ull << 60)) {
  289. hrs.value = (double)size / (1ull << 60);
  290. hrs.suffix = " EiB";
  291. } else if (size >= (1ull << 50)) {
  292. hrs.value = (double)size / (1ull << 50);
  293. hrs.suffix = " PiB";
  294. } else if (size >= (1ull << 40)) {
  295. hrs.value = (double)size / (1ull << 40);
  296. hrs.suffix = " TiB";
  297. } else if (size >= (1ull << 30)) {
  298. hrs.value = (double)size / (1ull << 30);
  299. hrs.suffix = " GiB";
  300. } else if (size >= (1ull << 20)) {
  301. hrs.value = (double)size / (1ull << 20);
  302. hrs.suffix = " MiB";
  303. } else if (size >= (1ull << 10)) {
  304. hrs.value = (double)size / (1ull << 10);
  305. hrs.suffix = " KiB";
  306. } else {
  307. hrs.value = (double)size;
  308. hrs.suffix = " B";
  309. }
  310. if (hrs.value >= 100 || (U64)hrs.value == size) {
  311. hrs.precision = 0;
  312. } else if (hrs.value >= 10) {
  313. hrs.precision = 1;
  314. } else if (hrs.value > 1) {
  315. hrs.precision = 2;
  316. } else {
  317. hrs.precision = 3;
  318. }
  319. }
  320. return hrs;
  321. }
  322. U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles)
  323. {
  324. U64 total = 0;
  325. unsigned n;
  326. for (n=0; n<nbFiles; n++) {
  327. U64 const size = UTIL_getFileSize(fileNamesTable[n]);
  328. if (size == UTIL_FILESIZE_UNKNOWN) return UTIL_FILESIZE_UNKNOWN;
  329. total += size;
  330. }
  331. return total;
  332. }
  333. /* condition : @file must be valid, and not have reached its end.
  334. * @return : length of line written into @buf, ended with `\0` instead of '\n',
  335. * or 0, if there is no new line */
  336. static size_t readLineFromFile(char* buf, size_t len, FILE* file)
  337. {
  338. assert(!feof(file));
  339. if ( fgets(buf, (int) len, file) == NULL ) return 0;
  340. { size_t linelen = strlen(buf);
  341. if (strlen(buf)==0) return 0;
  342. if (buf[linelen-1] == '\n') linelen--;
  343. buf[linelen] = '\0';
  344. return linelen+1;
  345. }
  346. }
  347. /* Conditions :
  348. * size of @inputFileName file must be < @dstCapacity
  349. * @dst must be initialized
  350. * @return : nb of lines
  351. * or -1 if there's an error
  352. */
  353. static int
  354. readLinesFromFile(void* dst, size_t dstCapacity,
  355. const char* inputFileName)
  356. {
  357. int nbFiles = 0;
  358. size_t pos = 0;
  359. char* const buf = (char*)dst;
  360. FILE* const inputFile = fopen(inputFileName, "r");
  361. assert(dst != NULL);
  362. if(!inputFile) {
  363. if (g_utilDisplayLevel >= 1) perror("zstd:util:readLinesFromFile");
  364. return -1;
  365. }
  366. while ( !feof(inputFile) ) {
  367. size_t const lineLength = readLineFromFile(buf+pos, dstCapacity-pos, inputFile);
  368. if (lineLength == 0) break;
  369. assert(pos + lineLength < dstCapacity);
  370. pos += lineLength;
  371. ++nbFiles;
  372. }
  373. CONTROL( fclose(inputFile) == 0 );
  374. return nbFiles;
  375. }
  376. /*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/
  377. FileNamesTable*
  378. UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
  379. {
  380. size_t nbFiles = 0;
  381. char* buf;
  382. size_t bufSize;
  383. size_t pos = 0;
  384. stat_t statbuf;
  385. if (!UTIL_stat(inputFileName, &statbuf) || !UTIL_isRegularFileStat(&statbuf))
  386. return NULL;
  387. { U64 const inputFileSize = UTIL_getFileSizeStat(&statbuf);
  388. if(inputFileSize > MAX_FILE_OF_FILE_NAMES_SIZE)
  389. return NULL;
  390. bufSize = (size_t)(inputFileSize + 1); /* (+1) to add '\0' at the end of last filename */
  391. }
  392. buf = (char*) malloc(bufSize);
  393. CONTROL( buf != NULL );
  394. { int const ret_nbFiles = readLinesFromFile(buf, bufSize, inputFileName);
  395. if (ret_nbFiles <= 0) {
  396. free(buf);
  397. return NULL;
  398. }
  399. nbFiles = (size_t)ret_nbFiles;
  400. }
  401. { const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable));
  402. CONTROL(filenamesTable != NULL);
  403. { size_t fnb;
  404. for (fnb = 0, pos = 0; fnb < nbFiles; fnb++) {
  405. filenamesTable[fnb] = buf+pos;
  406. pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */
  407. } }
  408. assert(pos <= bufSize);
  409. return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf);
  410. }
  411. }
  412. static FileNamesTable*
  413. UTIL_assembleFileNamesTable2(const char** filenames, size_t tableSize, size_t tableCapacity, char* buf)
  414. {
  415. FileNamesTable* const table = (FileNamesTable*) malloc(sizeof(*table));
  416. CONTROL(table != NULL);
  417. table->fileNames = filenames;
  418. table->buf = buf;
  419. table->tableSize = tableSize;
  420. table->tableCapacity = tableCapacity;
  421. return table;
  422. }
  423. FileNamesTable*
  424. UTIL_assembleFileNamesTable(const char** filenames, size_t tableSize, char* buf)
  425. {
  426. return UTIL_assembleFileNamesTable2(filenames, tableSize, tableSize, buf);
  427. }
  428. void UTIL_freeFileNamesTable(FileNamesTable* table)
  429. {
  430. if (table==NULL) return;
  431. free((void*)table->fileNames);
  432. free(table->buf);
  433. free(table);
  434. }
  435. FileNamesTable* UTIL_allocateFileNamesTable(size_t tableSize)
  436. {
  437. const char** const fnTable = (const char**)malloc(tableSize * sizeof(*fnTable));
  438. FileNamesTable* fnt;
  439. if (fnTable==NULL) return NULL;
  440. fnt = UTIL_assembleFileNamesTable(fnTable, tableSize, NULL);
  441. fnt->tableSize = 0; /* the table is empty */
  442. return fnt;
  443. }
  444. void UTIL_refFilename(FileNamesTable* fnt, const char* filename)
  445. {
  446. assert(fnt->tableSize < fnt->tableCapacity);
  447. fnt->fileNames[fnt->tableSize] = filename;
  448. fnt->tableSize++;
  449. }
  450. static size_t getTotalTableSize(FileNamesTable* table)
  451. {
  452. size_t fnb = 0, totalSize = 0;
  453. for(fnb = 0 ; fnb < table->tableSize && table->fileNames[fnb] ; ++fnb) {
  454. totalSize += strlen(table->fileNames[fnb]) + 1; /* +1 to add '\0' at the end of each fileName */
  455. }
  456. return totalSize;
  457. }
  458. FileNamesTable*
  459. UTIL_mergeFileNamesTable(FileNamesTable* table1, FileNamesTable* table2)
  460. {
  461. unsigned newTableIdx = 0;
  462. size_t pos = 0;
  463. size_t newTotalTableSize;
  464. char* buf;
  465. FileNamesTable* const newTable = UTIL_assembleFileNamesTable(NULL, 0, NULL);
  466. CONTROL( newTable != NULL );
  467. newTotalTableSize = getTotalTableSize(table1) + getTotalTableSize(table2);
  468. buf = (char*) calloc(newTotalTableSize, sizeof(*buf));
  469. CONTROL ( buf != NULL );
  470. newTable->buf = buf;
  471. newTable->tableSize = table1->tableSize + table2->tableSize;
  472. newTable->fileNames = (const char **) calloc(newTable->tableSize, sizeof(*(newTable->fileNames)));
  473. CONTROL ( newTable->fileNames != NULL );
  474. { unsigned idx1;
  475. for( idx1=0 ; (idx1 < table1->tableSize) && table1->fileNames[idx1] && (pos < newTotalTableSize); ++idx1, ++newTableIdx) {
  476. size_t const curLen = strlen(table1->fileNames[idx1]);
  477. memcpy(buf+pos, table1->fileNames[idx1], curLen);
  478. assert(newTableIdx <= newTable->tableSize);
  479. newTable->fileNames[newTableIdx] = buf+pos;
  480. pos += curLen+1;
  481. } }
  482. { unsigned idx2;
  483. for( idx2=0 ; (idx2 < table2->tableSize) && table2->fileNames[idx2] && (pos < newTotalTableSize) ; ++idx2, ++newTableIdx) {
  484. size_t const curLen = strlen(table2->fileNames[idx2]);
  485. memcpy(buf+pos, table2->fileNames[idx2], curLen);
  486. assert(newTableIdx <= newTable->tableSize);
  487. newTable->fileNames[newTableIdx] = buf+pos;
  488. pos += curLen+1;
  489. } }
  490. assert(pos <= newTotalTableSize);
  491. newTable->tableSize = newTableIdx;
  492. UTIL_freeFileNamesTable(table1);
  493. UTIL_freeFileNamesTable(table2);
  494. return newTable;
  495. }
  496. #ifdef _WIN32
  497. static int UTIL_prepareFileList(const char* dirName,
  498. char** bufStart, size_t* pos,
  499. char** bufEnd, int followLinks)
  500. {
  501. char* path;
  502. size_t dirLength, pathLength;
  503. int nbFiles = 0;
  504. WIN32_FIND_DATAA cFile;
  505. HANDLE hFile;
  506. dirLength = strlen(dirName);
  507. path = (char*) malloc(dirLength + 3);
  508. if (!path) return 0;
  509. memcpy(path, dirName, dirLength);
  510. path[dirLength] = '\\';
  511. path[dirLength+1] = '*';
  512. path[dirLength+2] = 0;
  513. hFile=FindFirstFileA(path, &cFile);
  514. if (hFile == INVALID_HANDLE_VALUE) {
  515. UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName);
  516. return 0;
  517. }
  518. free(path);
  519. do {
  520. size_t const fnameLength = strlen(cFile.cFileName);
  521. path = (char*) malloc(dirLength + fnameLength + 2);
  522. if (!path) { FindClose(hFile); return 0; }
  523. memcpy(path, dirName, dirLength);
  524. path[dirLength] = '\\';
  525. memcpy(path+dirLength+1, cFile.cFileName, fnameLength);
  526. pathLength = dirLength+1+fnameLength;
  527. path[pathLength] = 0;
  528. if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  529. if ( strcmp (cFile.cFileName, "..") == 0
  530. || strcmp (cFile.cFileName, ".") == 0 )
  531. continue;
  532. /* Recursively call "UTIL_prepareFileList" with the new path. */
  533. nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks);
  534. if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
  535. } else if ( (cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
  536. || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
  537. || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) {
  538. if (*bufStart + *pos + pathLength >= *bufEnd) {
  539. ptrdiff_t const newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
  540. *bufStart = (char*)UTIL_realloc(*bufStart, newListSize);
  541. if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
  542. *bufEnd = *bufStart + newListSize;
  543. }
  544. if (*bufStart + *pos + pathLength < *bufEnd) {
  545. memcpy(*bufStart + *pos, path, pathLength+1 /* include final \0 */);
  546. *pos += pathLength + 1;
  547. nbFiles++;
  548. } }
  549. free(path);
  550. } while (FindNextFileA(hFile, &cFile));
  551. FindClose(hFile);
  552. return nbFiles;
  553. }
  554. #elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */
  555. static int UTIL_prepareFileList(const char *dirName,
  556. char** bufStart, size_t* pos,
  557. char** bufEnd, int followLinks)
  558. {
  559. DIR* dir;
  560. struct dirent * entry;
  561. size_t dirLength;
  562. int nbFiles = 0;
  563. if (!(dir = opendir(dirName))) {
  564. UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
  565. return 0;
  566. }
  567. dirLength = strlen(dirName);
  568. errno = 0;
  569. while ((entry = readdir(dir)) != NULL) {
  570. char* path;
  571. size_t fnameLength, pathLength;
  572. if (strcmp (entry->d_name, "..") == 0 ||
  573. strcmp (entry->d_name, ".") == 0) continue;
  574. fnameLength = strlen(entry->d_name);
  575. path = (char*) malloc(dirLength + fnameLength + 2);
  576. if (!path) { closedir(dir); return 0; }
  577. memcpy(path, dirName, dirLength);
  578. path[dirLength] = '/';
  579. memcpy(path+dirLength+1, entry->d_name, fnameLength);
  580. pathLength = dirLength+1+fnameLength;
  581. path[pathLength] = 0;
  582. if (!followLinks && UTIL_isLink(path)) {
  583. UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path);
  584. free(path);
  585. continue;
  586. }
  587. if (UTIL_isDirectory(path)) {
  588. nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */
  589. if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
  590. } else {
  591. if (*bufStart + *pos + pathLength >= *bufEnd) {
  592. ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE;
  593. assert(newListSize >= 0);
  594. *bufStart = (char*)UTIL_realloc(*bufStart, (size_t)newListSize);
  595. *bufEnd = *bufStart + newListSize;
  596. if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
  597. }
  598. if (*bufStart + *pos + pathLength < *bufEnd) {
  599. memcpy(*bufStart + *pos, path, pathLength + 1); /* with final \0 */
  600. *pos += pathLength + 1;
  601. nbFiles++;
  602. } }
  603. free(path);
  604. errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */
  605. }
  606. if (errno != 0) {
  607. UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s \n", dirName, strerror(errno));
  608. free(*bufStart);
  609. *bufStart = NULL;
  610. }
  611. closedir(dir);
  612. return nbFiles;
  613. }
  614. #else
  615. static int UTIL_prepareFileList(const char *dirName,
  616. char** bufStart, size_t* pos,
  617. char** bufEnd, int followLinks)
  618. {
  619. (void)bufStart; (void)bufEnd; (void)pos; (void)followLinks;
  620. UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE) \n", dirName);
  621. return 0;
  622. }
  623. #endif /* #ifdef _WIN32 */
  624. int UTIL_isCompressedFile(const char *inputName, const char *extensionList[])
  625. {
  626. const char* ext = UTIL_getFileExtension(inputName);
  627. while(*extensionList!=NULL)
  628. {
  629. const int isCompressedExtension = strcmp(ext,*extensionList);
  630. if(isCompressedExtension==0)
  631. return 1;
  632. ++extensionList;
  633. }
  634. return 0;
  635. }
  636. /*Utility function to get file extension from file */
  637. const char* UTIL_getFileExtension(const char* infilename)
  638. {
  639. const char* extension = strrchr(infilename, '.');
  640. if(!extension || extension==infilename) return "";
  641. return extension;
  642. }
  643. static int pathnameHas2Dots(const char *pathname)
  644. {
  645. /* We need to figure out whether any ".." present in the path is a whole
  646. * path token, which is the case if it is bordered on both sides by either
  647. * the beginning/end of the path or by a directory separator.
  648. */
  649. const char *needle = pathname;
  650. while (1) {
  651. needle = strstr(needle, "..");
  652. if (needle == NULL) {
  653. return 0;
  654. }
  655. if ((needle == pathname || needle[-1] == PATH_SEP)
  656. && (needle[2] == '\0' || needle[2] == PATH_SEP)) {
  657. return 1;
  658. }
  659. /* increment so we search for the next match */
  660. needle++;
  661. };
  662. return 0;
  663. }
  664. static int isFileNameValidForMirroredOutput(const char *filename)
  665. {
  666. return !pathnameHas2Dots(filename);
  667. }
  668. #define DIR_DEFAULT_MODE 0755
  669. static mode_t getDirMode(const char *dirName)
  670. {
  671. stat_t st;
  672. if (!UTIL_stat(dirName, &st)) {
  673. UTIL_DISPLAY("zstd: failed to get DIR stats %s: %s\n", dirName, strerror(errno));
  674. return DIR_DEFAULT_MODE;
  675. }
  676. if (!UTIL_isDirectoryStat(&st)) {
  677. UTIL_DISPLAY("zstd: expected directory: %s\n", dirName);
  678. return DIR_DEFAULT_MODE;
  679. }
  680. return st.st_mode;
  681. }
  682. static int makeDir(const char *dir, mode_t mode)
  683. {
  684. #if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__)
  685. int ret = _mkdir(dir);
  686. (void) mode;
  687. #else
  688. int ret = mkdir(dir, mode);
  689. #endif
  690. if (ret != 0) {
  691. if (errno == EEXIST)
  692. return 0;
  693. UTIL_DISPLAY("zstd: failed to create DIR %s: %s\n", dir, strerror(errno));
  694. }
  695. return ret;
  696. }
  697. /* this function requires a mutable input string */
  698. static void convertPathnameToDirName(char *pathname)
  699. {
  700. size_t len = 0;
  701. char* pos = NULL;
  702. /* get dir name from pathname similar to 'dirname()' */
  703. assert(pathname != NULL);
  704. /* remove trailing '/' chars */
  705. len = strlen(pathname);
  706. assert(len > 0);
  707. while (pathname[len] == PATH_SEP) {
  708. pathname[len] = '\0';
  709. len--;
  710. }
  711. if (len == 0) return;
  712. /* if input is a single file, return '.' instead. i.e.
  713. * "xyz/abc/file.txt" => "xyz/abc"
  714. "./file.txt" => "."
  715. "file.txt" => "."
  716. */
  717. pos = strrchr(pathname, PATH_SEP);
  718. if (pos == NULL) {
  719. pathname[0] = '.';
  720. pathname[1] = '\0';
  721. } else {
  722. *pos = '\0';
  723. }
  724. }
  725. /* pathname must be valid */
  726. static const char* trimLeadingRootChar(const char *pathname)
  727. {
  728. assert(pathname != NULL);
  729. if (pathname[0] == PATH_SEP)
  730. return pathname + 1;
  731. return pathname;
  732. }
  733. /* pathname must be valid */
  734. static const char* trimLeadingCurrentDirConst(const char *pathname)
  735. {
  736. assert(pathname != NULL);
  737. if ((pathname[0] == '.') && (pathname[1] == PATH_SEP))
  738. return pathname + 2;
  739. return pathname;
  740. }
  741. static char*
  742. trimLeadingCurrentDir(char *pathname)
  743. {
  744. /* 'union charunion' can do const-cast without compiler warning */
  745. union charunion {
  746. char *chr;
  747. const char* cchr;
  748. } ptr;
  749. ptr.cchr = trimLeadingCurrentDirConst(pathname);
  750. return ptr.chr;
  751. }
  752. /* remove leading './' or '/' chars here */
  753. static const char * trimPath(const char *pathname)
  754. {
  755. return trimLeadingRootChar(
  756. trimLeadingCurrentDirConst(pathname));
  757. }
  758. static char* mallocAndJoin2Dir(const char *dir1, const char *dir2)
  759. {
  760. const size_t dir1Size = strlen(dir1);
  761. const size_t dir2Size = strlen(dir2);
  762. char *outDirBuffer, *buffer, trailingChar;
  763. assert(dir1 != NULL && dir2 != NULL);
  764. outDirBuffer = (char *) malloc(dir1Size + dir2Size + 2);
  765. CONTROL(outDirBuffer != NULL);
  766. memcpy(outDirBuffer, dir1, dir1Size);
  767. outDirBuffer[dir1Size] = '\0';
  768. if (dir2[0] == '.')
  769. return outDirBuffer;
  770. buffer = outDirBuffer + dir1Size;
  771. trailingChar = *(buffer - 1);
  772. if (trailingChar != PATH_SEP) {
  773. *buffer = PATH_SEP;
  774. buffer++;
  775. }
  776. memcpy(buffer, dir2, dir2Size);
  777. buffer[dir2Size] = '\0';
  778. return outDirBuffer;
  779. }
  780. /* this function will return NULL if input srcFileName is not valid name for mirrored output path */
  781. char* UTIL_createMirroredDestDirName(const char* srcFileName, const char* outDirRootName)
  782. {
  783. char* pathname = NULL;
  784. if (!isFileNameValidForMirroredOutput(srcFileName))
  785. return NULL;
  786. pathname = mallocAndJoin2Dir(outDirRootName, trimPath(srcFileName));
  787. convertPathnameToDirName(pathname);
  788. return pathname;
  789. }
  790. static int
  791. mirrorSrcDir(char* srcDirName, const char* outDirName)
  792. {
  793. mode_t srcMode;
  794. int status = 0;
  795. char* newDir = mallocAndJoin2Dir(outDirName, trimPath(srcDirName));
  796. if (!newDir)
  797. return -ENOMEM;
  798. srcMode = getDirMode(srcDirName);
  799. status = makeDir(newDir, srcMode);
  800. free(newDir);
  801. return status;
  802. }
  803. static int
  804. mirrorSrcDirRecursive(char* srcDirName, const char* outDirName)
  805. {
  806. int status = 0;
  807. char* pp = trimLeadingCurrentDir(srcDirName);
  808. char* sp = NULL;
  809. while ((sp = strchr(pp, PATH_SEP)) != NULL) {
  810. if (sp != pp) {
  811. *sp = '\0';
  812. status = mirrorSrcDir(srcDirName, outDirName);
  813. if (status != 0)
  814. return status;
  815. *sp = PATH_SEP;
  816. }
  817. pp = sp + 1;
  818. }
  819. status = mirrorSrcDir(srcDirName, outDirName);
  820. return status;
  821. }
  822. static void
  823. makeMirroredDestDirsWithSameSrcDirMode(char** srcDirNames, unsigned nbFile, const char* outDirName)
  824. {
  825. unsigned int i = 0;
  826. for (i = 0; i < nbFile; i++)
  827. mirrorSrcDirRecursive(srcDirNames[i], outDirName);
  828. }
  829. static int
  830. firstIsParentOrSameDirOfSecond(const char* firstDir, const char* secondDir)
  831. {
  832. size_t firstDirLen = strlen(firstDir),
  833. secondDirLen = strlen(secondDir);
  834. return firstDirLen <= secondDirLen &&
  835. (secondDir[firstDirLen] == PATH_SEP || secondDir[firstDirLen] == '\0') &&
  836. 0 == strncmp(firstDir, secondDir, firstDirLen);
  837. }
  838. static int compareDir(const void* pathname1, const void* pathname2) {
  839. /* sort it after remove the leading '/' or './'*/
  840. const char* s1 = trimPath(*(char * const *) pathname1);
  841. const char* s2 = trimPath(*(char * const *) pathname2);
  842. return strcmp(s1, s2);
  843. }
  844. static void
  845. makeUniqueMirroredDestDirs(char** srcDirNames, unsigned nbFile, const char* outDirName)
  846. {
  847. unsigned int i = 0, uniqueDirNr = 0;
  848. char** uniqueDirNames = NULL;
  849. if (nbFile == 0)
  850. return;
  851. uniqueDirNames = (char** ) malloc(nbFile * sizeof (char *));
  852. CONTROL(uniqueDirNames != NULL);
  853. /* if dirs is "a/b/c" and "a/b/c/d", we only need call:
  854. * we just need "a/b/c/d" */
  855. qsort((void *)srcDirNames, nbFile, sizeof(char*), compareDir);
  856. uniqueDirNr = 1;
  857. uniqueDirNames[uniqueDirNr - 1] = srcDirNames[0];
  858. for (i = 1; i < nbFile; i++) {
  859. char* prevDirName = srcDirNames[i - 1];
  860. char* currDirName = srcDirNames[i];
  861. /* note: we always compare trimmed path, i.e.:
  862. * src dir of "./foo" and "/foo" will be both saved into:
  863. * "outDirName/foo/" */
  864. if (!firstIsParentOrSameDirOfSecond(trimPath(prevDirName),
  865. trimPath(currDirName)))
  866. uniqueDirNr++;
  867. /* we need maintain original src dir name instead of trimmed
  868. * dir, so we can retrieve the original src dir's mode_t */
  869. uniqueDirNames[uniqueDirNr - 1] = currDirName;
  870. }
  871. makeMirroredDestDirsWithSameSrcDirMode(uniqueDirNames, uniqueDirNr, outDirName);
  872. free(uniqueDirNames);
  873. }
  874. static void
  875. makeMirroredDestDirs(char** srcFileNames, unsigned nbFile, const char* outDirName)
  876. {
  877. unsigned int i = 0;
  878. for (i = 0; i < nbFile; ++i)
  879. convertPathnameToDirName(srcFileNames[i]);
  880. makeUniqueMirroredDestDirs(srcFileNames, nbFile, outDirName);
  881. }
  882. void UTIL_mirrorSourceFilesDirectories(const char** inFileNames, unsigned int nbFile, const char* outDirName)
  883. {
  884. unsigned int i = 0, validFilenamesNr = 0;
  885. char** srcFileNames = (char **) malloc(nbFile * sizeof (char *));
  886. CONTROL(srcFileNames != NULL);
  887. /* check input filenames is valid */
  888. for (i = 0; i < nbFile; ++i) {
  889. if (isFileNameValidForMirroredOutput(inFileNames[i])) {
  890. char* fname = STRDUP(inFileNames[i]);
  891. CONTROL(fname != NULL);
  892. srcFileNames[validFilenamesNr++] = fname;
  893. }
  894. }
  895. if (validFilenamesNr > 0) {
  896. makeDir(outDirName, DIR_DEFAULT_MODE);
  897. makeMirroredDestDirs(srcFileNames, validFilenamesNr, outDirName);
  898. }
  899. for (i = 0; i < validFilenamesNr; i++)
  900. free(srcFileNames[i]);
  901. free(srcFileNames);
  902. }
  903. FileNamesTable*
  904. UTIL_createExpandedFNT(const char* const* inputNames, size_t nbIfns, int followLinks)
  905. {
  906. unsigned nbFiles;
  907. char* buf = (char*)malloc(LIST_SIZE_INCREASE);
  908. char* bufend = buf + LIST_SIZE_INCREASE;
  909. if (!buf) return NULL;
  910. { size_t ifnNb, pos;
  911. for (ifnNb=0, pos=0, nbFiles=0; ifnNb<nbIfns; ifnNb++) {
  912. if (!UTIL_isDirectory(inputNames[ifnNb])) {
  913. size_t const len = strlen(inputNames[ifnNb]);
  914. if (buf + pos + len >= bufend) {
  915. ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE;
  916. assert(newListSize >= 0);
  917. buf = (char*)UTIL_realloc(buf, (size_t)newListSize);
  918. if (!buf) return NULL;
  919. bufend = buf + newListSize;
  920. }
  921. if (buf + pos + len < bufend) {
  922. memcpy(buf+pos, inputNames[ifnNb], len+1); /* including final \0 */
  923. pos += len + 1;
  924. nbFiles++;
  925. }
  926. } else {
  927. nbFiles += (unsigned)UTIL_prepareFileList(inputNames[ifnNb], &buf, &pos, &bufend, followLinks);
  928. if (buf == NULL) return NULL;
  929. } } }
  930. /* note : even if nbFiles==0, function returns a valid, though empty, FileNamesTable* object */
  931. { size_t ifnNb, pos;
  932. size_t const fntCapacity = nbFiles + 1; /* minimum 1, allows adding one reference, typically stdin */
  933. const char** const fileNamesTable = (const char**)malloc(fntCapacity * sizeof(*fileNamesTable));
  934. if (!fileNamesTable) { free(buf); return NULL; }
  935. for (ifnNb = 0, pos = 0; ifnNb < nbFiles; ifnNb++) {
  936. fileNamesTable[ifnNb] = buf + pos;
  937. if (buf + pos > bufend) { free(buf); free((void*)fileNamesTable); return NULL; }
  938. pos += strlen(fileNamesTable[ifnNb]) + 1;
  939. }
  940. return UTIL_assembleFileNamesTable2(fileNamesTable, nbFiles, fntCapacity, buf);
  941. }
  942. }
  943. void UTIL_expandFNT(FileNamesTable** fnt, int followLinks)
  944. {
  945. FileNamesTable* const newFNT = UTIL_createExpandedFNT((*fnt)->fileNames, (*fnt)->tableSize, followLinks);
  946. CONTROL(newFNT != NULL);
  947. UTIL_freeFileNamesTable(*fnt);
  948. *fnt = newFNT;
  949. }
  950. FileNamesTable* UTIL_createFNT_fromROTable(const char** filenames, size_t nbFilenames)
  951. {
  952. size_t const sizeof_FNTable = nbFilenames * sizeof(*filenames);
  953. const char** const newFNTable = (const char**)malloc(sizeof_FNTable);
  954. if (newFNTable==NULL) return NULL;
  955. memcpy((void*)newFNTable, filenames, sizeof_FNTable); /* void* : mitigate a Visual compiler bug or limitation */
  956. return UTIL_assembleFileNamesTable(newFNTable, nbFilenames, NULL);
  957. }
  958. /*-****************************************
  959. * count the number of cores
  960. ******************************************/
  961. #if defined(_WIN32) || defined(WIN32)
  962. #include <windows.h>
  963. typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
  964. DWORD CountSetBits(ULONG_PTR bitMask)
  965. {
  966. DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;
  967. DWORD bitSetCount = 0;
  968. ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;
  969. DWORD i;
  970. for (i = 0; i <= LSHIFT; ++i)
  971. {
  972. bitSetCount += ((bitMask & bitTest)?1:0);
  973. bitTest/=2;
  974. }
  975. return bitSetCount;
  976. }
  977. int UTIL_countCores(int logical)
  978. {
  979. static int numCores = 0;
  980. if (numCores != 0) return numCores;
  981. { LPFN_GLPI glpi;
  982. BOOL done = FALSE;
  983. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
  984. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
  985. DWORD returnLength = 0;
  986. size_t byteOffset = 0;
  987. #if defined(_MSC_VER)
  988. /* Visual Studio does not like the following cast */
  989. # pragma warning( disable : 4054 ) /* conversion from function ptr to data ptr */
  990. # pragma warning( disable : 4055 ) /* conversion from data ptr to function ptr */
  991. #endif
  992. glpi = (LPFN_GLPI)(void*)GetProcAddress(GetModuleHandle(TEXT("kernel32")),
  993. "GetLogicalProcessorInformation");
  994. if (glpi == NULL) {
  995. goto failed;
  996. }
  997. while(!done) {
  998. DWORD rc = glpi(buffer, &returnLength);
  999. if (FALSE == rc) {
  1000. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  1001. if (buffer)
  1002. free(buffer);
  1003. buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
  1004. if (buffer == NULL) {
  1005. perror("zstd");
  1006. exit(1);
  1007. }
  1008. } else {
  1009. /* some other error */
  1010. goto failed;
  1011. }
  1012. } else {
  1013. done = TRUE;
  1014. } }
  1015. ptr = buffer;
  1016. while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
  1017. if (ptr->Relationship == RelationProcessorCore) {
  1018. if (logical)
  1019. numCores += CountSetBits(ptr->ProcessorMask);
  1020. else
  1021. numCores++;
  1022. }
  1023. ptr++;
  1024. byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  1025. }
  1026. free(buffer);
  1027. return numCores;
  1028. }
  1029. failed:
  1030. /* try to fall back on GetSystemInfo */
  1031. { SYSTEM_INFO sysinfo;
  1032. GetSystemInfo(&sysinfo);
  1033. numCores = sysinfo.dwNumberOfProcessors;
  1034. if (numCores == 0) numCores = 1; /* just in case */
  1035. }
  1036. return numCores;
  1037. }
  1038. #elif defined(__APPLE__)
  1039. #include <sys/sysctl.h>
  1040. /* Use apple-provided syscall
  1041. * see: man 3 sysctl */
  1042. int UTIL_countCores(int logical)
  1043. {
  1044. static S32 numCores = 0; /* apple specifies int32_t */
  1045. if (numCores != 0) return numCores;
  1046. { size_t size = sizeof(S32);
  1047. int const ret = sysctlbyname(logical ? "hw.logicalcpu" : "hw.physicalcpu", &numCores, &size, NULL, 0);
  1048. if (ret != 0) {
  1049. if (errno == ENOENT) {
  1050. /* entry not present, fall back on 1 */
  1051. numCores = 1;
  1052. } else {
  1053. perror("zstd: can't get number of cpus");
  1054. exit(1);
  1055. }
  1056. }
  1057. return numCores;
  1058. }
  1059. }
  1060. #elif defined(__linux__)
  1061. /* parse /proc/cpuinfo
  1062. * siblings / cpu cores should give hyperthreading ratio
  1063. * otherwise fall back on sysconf */
  1064. int UTIL_countCores(int logical)
  1065. {
  1066. static int numCores = 0;
  1067. if (numCores != 0) return numCores;
  1068. numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
  1069. if (numCores == -1) {
  1070. /* value not queryable, fall back on 1 */
  1071. return numCores = 1;
  1072. }
  1073. /* try to determine if there's hyperthreading */
  1074. { FILE* const cpuinfo = fopen("/proc/cpuinfo", "r");
  1075. #define BUF_SIZE 80
  1076. char buff[BUF_SIZE];
  1077. int siblings = 0;
  1078. int cpu_cores = 0;
  1079. int ratio = 1;
  1080. if (cpuinfo == NULL) {
  1081. /* fall back on the sysconf value */
  1082. return numCores;
  1083. }
  1084. /* assume the cpu cores/siblings values will be constant across all
  1085. * present processors */
  1086. while (!feof(cpuinfo)) {
  1087. if (fgets(buff, BUF_SIZE, cpuinfo) != NULL) {
  1088. if (strncmp(buff, "siblings", 8) == 0) {
  1089. const char* const sep = strchr(buff, ':');
  1090. if (sep == NULL || *sep == '\0') {
  1091. /* formatting was broken? */
  1092. goto failed;
  1093. }
  1094. siblings = atoi(sep + 1);
  1095. }
  1096. if (strncmp(buff, "cpu cores", 9) == 0) {
  1097. const char* const sep = strchr(buff, ':');
  1098. if (sep == NULL || *sep == '\0') {
  1099. /* formatting was broken? */
  1100. goto failed;
  1101. }
  1102. cpu_cores = atoi(sep + 1);
  1103. }
  1104. } else if (ferror(cpuinfo)) {
  1105. /* fall back on the sysconf value */
  1106. goto failed;
  1107. } }
  1108. if (siblings && cpu_cores && siblings > cpu_cores) {
  1109. ratio = siblings / cpu_cores;
  1110. }
  1111. if (ratio && numCores > ratio && !logical) {
  1112. numCores = numCores / ratio;
  1113. }
  1114. failed:
  1115. fclose(cpuinfo);
  1116. return numCores;
  1117. }
  1118. }
  1119. #elif defined(__FreeBSD__)
  1120. #include <sys/param.h>
  1121. #include <sys/sysctl.h>
  1122. /* Use physical core sysctl when available
  1123. * see: man 4 smp, man 3 sysctl */
  1124. int UTIL_countCores(int logical)
  1125. {
  1126. static int numCores = 0; /* freebsd sysctl is native int sized */
  1127. #if __FreeBSD_version >= 1300008
  1128. static int perCore = 1;
  1129. #endif
  1130. if (numCores != 0) return numCores;
  1131. #if __FreeBSD_version >= 1300008
  1132. { size_t size = sizeof(numCores);
  1133. int ret = sysctlbyname("kern.smp.cores", &numCores, &size, NULL, 0);
  1134. if (ret == 0) {
  1135. if (logical) {
  1136. ret = sysctlbyname("kern.smp.threads_per_core", &perCore, &size, NULL, 0);
  1137. /* default to physical cores if logical cannot be read */
  1138. if (ret == 0)
  1139. numCores *= perCore;
  1140. }
  1141. return numCores;
  1142. }
  1143. if (errno != ENOENT) {
  1144. perror("zstd: can't get number of cpus");
  1145. exit(1);
  1146. }
  1147. /* sysctl not present, fall through to older sysconf method */
  1148. }
  1149. #else
  1150. /* suppress unused parameter warning */
  1151. (void) logical;
  1152. #endif
  1153. numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
  1154. if (numCores == -1) {
  1155. /* value not queryable, fall back on 1 */
  1156. numCores = 1;
  1157. }
  1158. return numCores;
  1159. }
  1160. #elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
  1161. /* Use POSIX sysconf
  1162. * see: man 3 sysconf */
  1163. int UTIL_countCores(int logical)
  1164. {
  1165. static int numCores = 0;
  1166. /* suppress unused parameter warning */
  1167. (void)logical;
  1168. if (numCores != 0) return numCores;
  1169. numCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
  1170. if (numCores == -1) {
  1171. /* value not queryable, fall back on 1 */
  1172. return numCores = 1;
  1173. }
  1174. return numCores;
  1175. }
  1176. #else
  1177. int UTIL_countCores(int logical)
  1178. {
  1179. /* assume 1 */
  1180. return 1;
  1181. }
  1182. #endif
  1183. int UTIL_countPhysicalCores(void)
  1184. {
  1185. return UTIL_countCores(0);
  1186. }
  1187. int UTIL_countLogicalCores(void)
  1188. {
  1189. return UTIL_countCores(1);
  1190. }
  1191. #if defined (__cplusplus)
  1192. }
  1193. #endif