Реализация mkstemp () для win32 - PullRequest
10 голосов
/ 17 мая 2011

Может кто-нибудь указать мне на код, который реализует mkstemp () (C / C ++) на Win32, или очень близкий аналог.

Должно быть без гонки.

Это должно выглядеть как

#include <windows.h>
#include <io.h>

// port of mkstemp() to win32. race-free.
// behaviour as described in http://linux.die.net/man/3/mkstemp
// 
int mkstemp(char *template) {
     ...
}

Спасибо

Ответы [ 3 ]

6 голосов
/ 17 мая 2011

Вы можете использовать следующую функцию, извлеченную из библиотеки wcecompat (из файла 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;
}

Он определяет O_EXCL как;

#define _O_EXCL         0x0400
#define O_EXCL          _O_EXCL

Вы можете легко извлечь из него поддержку mkstemp.

3 голосов
/ 18 июля 2013

На самом деле, использование _mktemp_s () является идеей очень плохой - только 26 возможных кандидатов на имена файлов в любом контексте, и, с таким ограниченным диапазоном, который нужно атаковать, он выставляет то самое состояние гонки, чтоmkstemp () предназначен для преодоления.Тем не менее, другое предлагаемое решение, хотя и намного лучше, также является недостатком, поскольку оно присваивает 62 степени свободы в выборе замещающих символов имени файла, тогда как нечувствительность к регистру файловой системы Windows потребляет 26 из них, таким образом, оставляя только 36;это имеет эффект взвешивания вероятности выбора любого логически различимого буквенного символа в два раза больше, чем для числового значения.

Имея это в виду, я разместил патч MinGW здесь: https://sourceforge.net/p/mingw/bugs/2003/

В случае принятия это официально добавит mkstemp () и mkdtemp () к стандартному дистрибутиву MinGW.

0 голосов
/ 17 сентября 2012

Вы можете использовать функцию _mktemp_s () или любой из ее вариантов:

errno_t _mktemp_s(
   char *template,
   size_t sizeInChars
);

где:

  • template : Шаблон имени файла.
  • sizeInChars : Размер буфера в однобайтовых символах в _mktemp_s;широкие символы в _wmktemp_s, включая нулевой терминатор.

Возвращает 0 при успехе и код ошибки при ошибке.Обратите внимание, что функция изменяет аргумент template.

...