root/src/dps8/utfile.c

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

DEFINITIONS

This source file includes following definitions.
  1. 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-2022 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 <unistd.h>
  34 
  35 #define MAX_MKSTEMPS_TRIES 10000
  36 
  37 #if defined(__MINGW64__) || defined(__MINGW32__)
  38 # include "bsd_random.h"
  39 # define random  bsd_random
  40 # define srandom bsd_srandom
  41 #endif /* if defined(__MINGW64__) || defined(__MINGW32__) */
  42 
  43 #undef FREE
  44 #ifdef TESTING
  45 # define FREE(p) free(p)
  46 #else
  47 # define FREE(p) do  \
  48   {                  \
  49     free((p));       \
  50     (p) = NULL;      \
  51   } while(0)
  52 #endif /* ifdef TESTING */
  53 
  54 static char valid_file_name_chars[]
  55   = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  56 
  57  /*
  58   * This is a minimal portable replacement for the mkstemps
  59   * function, which is not available on all platforms.
  60   */
  61 
  62 int
  63 utfile_mkstemps(char *request_pattern, int suffix_length)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65   long pattern_length;
  66   int st1ret;
  67   char *mask_pointer;
  68   struct timespec st1;
  69 
  70   char *pattern = strdup(request_pattern);
  71   if (!pattern)
  72     {
  73       fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
  74                __func__, __FILE__, __LINE__);
  75 #if defined(USE_BACKTRACE)
  76 # ifdef SIGUSR2
  77       (void)raise(SIGUSR2);
  78       /*NOTREACHED*/ /* unreachable */
  79 # endif /* ifdef SIGUSR2 */
  80 #endif /* if defined(USE_BACKTRACE) */
  81       abort();
  82     }
  83 
  84   pattern_length = (long) strlen(pattern);
  85 
  86 #ifdef USE_MONOTONIC
  87   st1ret = clock_gettime(CLOCK_MONOTONIC, &st1);
  88 #else
  89   st1ret = clock_gettime(CLOCK_REALTIME, &st1);
  90 #endif /* ifdef USE_MONOTONIC */
  91   if (st1ret != 0)
  92     {
  93       fprintf (stderr, "\rFATAL: clock_gettime failure! Aborting at %s[%s:%d]\r\n",
  94                __func__, __FILE__, __LINE__);
  95 #if defined(USE_BACKTRACE)
  96 # ifdef SIGUSR2
  97       (void)raise(SIGUSR2);
  98       /*NOTREACHED*/ /* unreachable */
  99 # endif /* ifdef SIGUSR2 */
 100 #endif /* if defined(USE_BACKTRACE) */
 101       abort();
 102     }
 103 
 104   srandom((unsigned int)(getpid() ^ (long)((1LL + (long long)st1.tv_nsec) * (1LL + (long long)st1.tv_sec))));
 105 
 106   if (( (long) pattern_length - 6 ) < (long) suffix_length)
 107   {
 108     FREE(pattern);
 109     return ( -1 );
 110   }
 111 
 112   long mask_offset = (long) pattern_length - ( 6 + (long) suffix_length );
 113 
 114   if (strncmp(&pattern[mask_offset], "XXXXXX", 6))
 115   {
 116     FREE(pattern);
 117     return ( -1 );
 118   }
 119 
 120   mask_pointer = &pattern[mask_offset];
 121 
 122   long valid_char_count = (long) strlen(valid_file_name_chars);
 123 
 124   if (valid_char_count < 1)
 125     {
 126       FREE(pattern);
 127       return ( -1 );
 128     }
 129 
 130   for (int count = 0; count < MAX_MKSTEMPS_TRIES; count++)
 131   {
 132     for (int mask_index = 0; mask_index < 6; mask_index++)
 133     {
 134       mask_pointer[mask_index]
 135         = valid_file_name_chars[random() % valid_char_count];
 136     }
 137 
 138     int fd = open(pattern, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
 139 
 140     if (fd >= 0)
 141     {
 142       FREE(pattern);
 143       return ( fd );
 144     }
 145 
 146     /*
 147      * If the error is not "file already exists",
 148      * or is a directory, then we just bail out.
 149      */
 150 
 151     if (( errno != EEXIST ) && ( errno != EISDIR ))
 152     {
 153       break;
 154     }
 155   }
 156 
 157   /*
 158    * If we get here, we were unable to create
 159    * a unique file name despite many of tries.
 160    */
 161 
 162   FREE(pattern);
 163   return ( -1 );
 164 }

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