The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/zstd/programs/util.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e1941758ed6044fb1fb7ffdc004b7c7a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.