root/src/dps8/utfile.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hash32s
  2. utfile_mkstemps

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 485f7d3b-f630-11ec-953b-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2021-2023 The DPS8M Development Team
   9  *
  10  * All rights reserved.
  11  *
  12  * This software is made available under the terms of the ICU
  13  * License, version 1.8.1 or later.  For more details, see the
  14  * LICENSE.md file at the top-level directory of this distribution.
  15  *
  16  * ---------------------------------------------------------------------------
  17  */
  18 
  19 #include <ctype.h>
  20 #include <signal.h>
  21 #include <errno.h>
  22 #include <fcntl.h>
  23 #include <stdio.h>
  24 #include <stdlib.h>
  25 #include <string.h>
  26 #if defined(__sunos) && defined(SYSV)
  27 # include <sys/param.h>
  28 #endif /* if defined(__sunos) && defined(SYSV) */
  29 #include <sys/stat.h>
  30 #include <sys/types.h>
  31 #include <time.h>
  32 #include <sys/time.h>
  33 #include <stdint.h>
  34 #include <unistd.h>
  35 
  36 #define MAX_MKSTEMPS_TRIES 10000
  37 
  38 #if defined(__MINGW64__) || defined(__MINGW32__)
  39 # include "bsd_random.h"
  40 # define random  bsd_random
  41 # define srandom bsd_srandom
  42 #endif /* if defined(__MINGW64__) || defined(__MINGW32__) */
  43 
  44 #if defined(__MACH__) && defined(__APPLE__) && \
  45   ( defined(__PPC__) || defined(_ARCH_PPC) )
  46 # include <mach/clock.h>
  47 # include <mach/mach.h>
  48 # ifdef MACOSXPPC
  49 #  undef MACOSXPPC
  50 # endif /* ifdef MACOSXPPC */
  51 # define MACOSXPPC 1
  52 #endif /* if defined(__MACH__) && defined(__APPLE__) &&
  53            ( defined(__PPC__) || defined(_ARCH_PPC) ) */
  54 
  55 #undef FREE
  56 #ifdef TESTING
  57 # define FREE(p) free(p)
  58 #else
  59 # define FREE(p) do  \
  60   {                  \
  61     free((p));       \
  62     (p) = NULL;      \
  63   } while(0)
  64 #endif /* ifdef TESTING */
  65 
  66 static char valid_file_name_chars[]
  67   = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  68 
  69 static inline uint32_t
  70 hash32s(const void *buf, size_t len, uint32_t h)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72   const unsigned char *p = buf;
  73 
  74   for (size_t i = 0; i < len; i++)
  75     h = h * 31 + p[i];
  76 
  77   h ^= h >> 17;
  78   h *= UINT32_C(0xed5ad4bb);
  79   h ^= h >> 11;
  80   h *= UINT32_C(0xac4c1b51);
  81   h ^= h >> 15;
  82   h *= UINT32_C(0x31848bab);
  83   h ^= h >> 14;
  84 
  85   return h;
  86 }
  87 
  88  /*
  89   * This is a minimal portable replacement for the mkstemps
  90   * function, which is not available on all platforms.
  91   */
  92 
  93 int
  94 utfile_mkstemps(char *request_pattern, int suffix_length)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96   long pattern_length;
  97   int st1ret;
  98   char *mask_pointer;
  99   struct timespec st1;
 100 
 101 #ifdef MACOSXPPC
 102   (void)st1;
 103 #endif /* ifdef MACOSXPPC */
 104   char *pattern = strdup(request_pattern);
 105   if (!pattern)
 106     {
 107       fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
 108                __func__, __FILE__, __LINE__);
 109 #if defined(USE_BACKTRACE)
 110 # ifdef SIGUSR2
 111       (void)raise(SIGUSR2);
 112       /*NOTREACHED*/ /* unreachable */
 113 # endif /* ifdef SIGUSR2 */
 114 #endif /* if defined(USE_BACKTRACE) */
 115       abort();
 116     }
 117 
 118   pattern_length = (long) strlen(pattern);
 119 
 120 #ifdef MACOSXPPC
 121 # undef USE_MONOTONIC
 122 #endif /* ifdef MACOSXPPC */
 123 #ifdef USE_MONOTONIC
 124   st1ret = clock_gettime(CLOCK_MONOTONIC, &st1);
 125 #else
 126 # ifdef MACOSXPPC
 127   clock_serv_t cclock;
 128   mach_timespec_t mts;
 129   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
 130   clock_get_time(cclock, &mts);
 131   mach_port_deallocate(mach_task_self(), cclock);
 132   st1.tv_sec = mts.tv_sec;
 133   st1.tv_nsec = mts.tv_nsec;
 134   st1ret = 0;
 135 # else
 136   st1ret = clock_gettime(CLOCK_REALTIME, &st1);
 137 # endif /* ifdef MACOSXPPC */
 138 #endif /* ifdef USE_MONOTONIC */
 139   if (st1ret != 0)
 140     {
 141       fprintf (stderr, "\rFATAL: clock_gettime failure! Aborting at %s[%s:%d]\r\n",
 142                __func__, __FILE__, __LINE__);
 143 #if defined(USE_BACKTRACE)
 144 # ifdef SIGUSR2
 145       (void)raise(SIGUSR2);
 146       /*NOTREACHED*/ /* unreachable */
 147 # endif /* ifdef SIGUSR2 */
 148 #endif /* if defined(USE_BACKTRACE) */
 149       abort();
 150     }
 151 
 152   uint32_t h = 0;  /* initial hash value */
 153 #if __STDC_VERSION__ < 201112L
 154   /* LINTED E_OLD_STYLE_FUNC_DECL */
 155   void *(*mallocptr)() = malloc;
 156   h = hash32s(&mallocptr, sizeof(mallocptr), h);
 157 #endif /* if __STDC_VERSION__ < 201112L */
 158   void *small = malloc(1);
 159   h = hash32s(&small, sizeof(small), h);
 160   FREE(small);
 161   void *big = malloc(1UL << 20);
 162   h = hash32s(&big, sizeof(big), h);
 163   FREE(big);
 164   void *ptr = &ptr;
 165   h = hash32s(&ptr, sizeof(ptr), h);
 166   time_t t = time(0);
 167   h = hash32s(&t, sizeof(t), h);
 168   for (int i = 0; i < 1000; i++)
 169     {
 170       unsigned long counter = 0;
 171       clock_t start = clock();
 172       while (clock() == start)
 173         {
 174           counter++;
 175         }
 176       h = hash32s(&start, sizeof(start), h);
 177       h = hash32s(&counter, sizeof(counter), h);
 178     }
 179   int mypid = (int)getpid();
 180   h = hash32s(&mypid, sizeof(mypid), h);
 181   char rnd[4];
 182   FILE *f = fopen("/dev/urandom", "rb");
 183   if (f)
 184     {
 185       if (fread(rnd, sizeof(rnd), 1, f))
 186         {
 187           h = hash32s(rnd, sizeof(rnd), h);
 188         }
 189       fclose(f);
 190     }
 191   srandom(h);
 192 
 193   if (( (long) pattern_length - 6 ) < (long) suffix_length)
 194   {
 195     FREE(pattern);
 196     return ( -1 );
 197   }
 198 
 199   long mask_offset = (long) pattern_length - ( 6 + (long) suffix_length );
 200 
 201   if (strncmp(&pattern[mask_offset], "XXXXXX", 6))
 202   {
 203     FREE(pattern);
 204     return ( -1 );
 205   }
 206 
 207   mask_pointer = &pattern[mask_offset];
 208 
 209   long valid_char_count = (long) strlen(valid_file_name_chars);
 210 
 211   if (valid_char_count < 1)
 212     {
 213       FREE(pattern);
 214       return ( -1 );
 215     }
 216 
 217   for (int count = 0; count < MAX_MKSTEMPS_TRIES; count++)
 218   {
 219     for (int mask_index = 0; mask_index < 6; mask_index++)
 220     {
 221       mask_pointer[mask_index]
 222         = valid_file_name_chars[random() % valid_char_count];
 223     }
 224 
 225     int fd = open(pattern, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
 226 
 227     if (fd >= 0)
 228     {
 229       FREE(pattern);
 230       return ( fd );
 231     }
 232 
 233     /*
 234      * If the error is not "file already exists",
 235      * or is a directory, then we just bail out.
 236      */
 237 
 238     if (( errno != EEXIST ) && ( errno != EISDIR ))
 239     {
 240       break;
 241     }
 242   }
 243 
 244   /*
 245    * If we get here, we were unable to create
 246    * a unique file name, despite many tries.
 247    */
 248 
 249   FREE(pattern);
 250   return ( -1 );
 251 }

/* [previous][next][first][last][top][bottom][index][help] */