mkstemp() implementation for win32

前端 未结 3 619
甜味超标
甜味超标 2020-12-31 11:17

Can anybody point me to the code that implements mkstemp() (C/C++) on Win32, or very close analog.

Must be race-free.

It\'s supposed to look like



        
相关标签:
3条回答
  • 2020-12-31 11:45

    Actually, using _mktemp_s() is a really bad idea -- only 26 possible file name candidates in any one context, and, with this limited range to be attacked, it exposes the very race condition that mkstemp() is designed to overcome. However, the other proposed solution, while much better, is also flawed, insofar as it attributes 62 degrees of freedom in the choice of substitute file name characters, whereas the case insensitivity of the Windows file system consumes 26 of these, thus leaving only 36; this has the effect of weighting the probability of selecting any logically distinguishable alphabetic character at double that for a numeric.

    With this in mind, I've posted a MinGW patch here: https://sourceforge.net/p/mingw/bugs/2003/

    If adopted, this will formally add both mkstemp() and mkdtemp() to the standard MinGW distribution.

    0 讨论(0)
  • 2020-12-31 11:46

    You can use _mktemp_s() function, or any of it's variations:

    errno_t _mktemp_s(
       char *template,
       size_t sizeInChars
    );
    

    where:

    • template: File name pattern.
    • sizeInChars: Size of the buffer in single-byte characters in _mktemp_s; wide characters in _wmktemp_s, including the null terminator.

    It returns 0 on success, and an error code on failure. Note that the function modifyes the template argument.

    0 讨论(0)
  • 2020-12-31 11:49

    You can use the following function which is extracted from wcecompat library (from file src/stdlib_extras.cpp)

    /* mkstemp extracted from libc/sysdeps/posix/tempname.c.  Copyright
       (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
    
       The GNU C Library is free software; you can redistribute it and/or
       modify it under the terms of the GNU Lesser General Public
       License as published by the Free Software Foundation; either
       version 2.1 of the License, or (at your option) any later version.  */
    
    static const char letters[] =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    
    /* Generate a temporary file name based on TMPL.  TMPL must match the
       rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
       does not exist at the time of the call to mkstemp.  TMPL is
       overwritten with the result.  */
    int
    mkstemp (char *tmpl)
    {
      int len;
      char *XXXXXX;
      static unsigned long long value;
      unsigned long long random_time_bits;
      unsigned int count;
      int fd = -1;
      int save_errno = errno;
    
      /* A lower bound on the number of temporary files to attempt to
         generate.  The maximum total number of temporary file names that
         can exist for a given template is 62**6.  It should never be
         necessary to try all these combinations.  Instead if a reasonable
         number of names is tried (we define reasonable as 62**3) fail to
         give the system administrator the chance to remove the problems.  */
    #define ATTEMPTS_MIN (62 * 62 * 62)
    
      /* The number of times to attempt to generate a temporary file.  To
         conform to POSIX, this must be no smaller than TMP_MAX.  */
    #if ATTEMPTS_MIN < TMP_MAX
      unsigned int attempts = TMP_MAX;
    #else
      unsigned int attempts = ATTEMPTS_MIN;
    #endif
    
      len = strlen (tmpl);
      if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
        {
          errno = EINVAL;
          return -1;
        }
    
    /* This is where the Xs start.  */
      XXXXXX = &tmpl[len - 6];
    
      /* Get some more or less random data.  */
      {
        SYSTEMTIME      stNow;
        FILETIME ftNow;
    
        // get system time
        GetSystemTime(&stNow);
        stNow.wMilliseconds = 500;
        if (!SystemTimeToFileTime(&stNow, &ftNow))
        {
            errno = -1;
            return -1;
        }
    
        random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32)
                            | (unsigned long long)ftNow.dwLowDateTime);
      }
      value += random_time_bits ^ (unsigned long long)GetCurrentThreadId ();
    
      for (count = 0; count < attempts; value += 7777, ++count)
        {
          unsigned long long v = value;
    
          /* Fill in the random bits.  */
          XXXXXX[0] = letters[v % 62];
          v /= 62;
          XXXXXX[1] = letters[v % 62];
          v /= 62;
          XXXXXX[2] = letters[v % 62];
          v /= 62;
          XXXXXX[3] = letters[v % 62];
          v /= 62;
          XXXXXX[4] = letters[v % 62];
          v /= 62;
          XXXXXX[5] = letters[v % 62];
    
          fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
          if (fd >= 0)
        {
          errno = save_errno;
          return fd;
        }
          else if (errno != EEXIST)
        return -1;
        }
    
      /* We got out of the loop because we ran out of combinations to try.  */
      errno = EEXIST;
      return -1;
    }
    

    It defines O_EXCL as;

    #define _O_EXCL         0x0400
    #define O_EXCL          _O_EXCL
    

    You can rip out mkstemp support out of it easily.

    0 讨论(0)
提交回复
热议问题