2011-05-17 9 views
7

¿Alguien me puede indicar el código que implementa mkstemp() (C/C++) en Win32, o análogo muy cercano.Implementación mkstemp() para win32

No debe tener carreras.

se supone que debe ser similar

#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) { 
    ... 
} 

Gracias

Respuesta

4

Puede utilizar la siguiente función que se extrae de wcecompat biblioteca (de archivo 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[] = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

/* 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; 
} 

Define O_EXCL como;

#define _O_EXCL   0x0400 
#define O_EXCL   _O_EXCL 

Puede extraer el soporte de mkstemp fácilmente.

+0

@Ismail, gracias, bingo. Eso es. – Andrei

+1

@Andrei, tenga en cuenta los defectos en esta implementación propuesta: atribuye incorrectamente 62 grados de libertad a la elección de caracteres de nombre de archivo, donde en realidad solo existen 36; (Las letras alfabéticas mayúsculas y minúsculas son indistinguibles en los nombres de archivo de MS-Windows). Además, Windows tiene mejores API para generar secuencias de números aleatorios criptográficamente seguras, que la técnica ilustrada aquí. –

+0

Como dice la parte superior del fragmento de código, esta implementación (incluidos los comentarios del código) se tomó de glibc, específicamente '__gen_tempname' en' sysdeps/posix/tempname.c'.Como señala @KeithMarshall, su conversión a Windows está incompleta y podría haber incluso más dificultades ... – josch

-1

Puede utilizar _mktemp_s() función, o cualquiera de sus variaciones:

errno_t _mktemp_s(
    char *template, 
    size_t sizeInChars 
); 

donde:

  • plantilla: Archivo patrón de nombre.
  • sizeInChars: Tamaño del búfer en caracteres de un solo byte en _mktemp_s; caracteres anchos en _wmktemp_s, incluido el terminador nulo.

Devuelve 0 en caso de éxito y un código de error en caso de error. Tenga en cuenta que la función modifica el argumento template.

+1

Usar '_mktemp_s()' es seguramente mejor que reinventar la rueda. Pero tenga en cuenta que, a diferencia de 'mkstemp()', *** de POSIX, no abre un archivo ni devuelve un fd ***. Simplemente devuelve una cadena de nombre de archivo y debe abrirla usted mismo. – MestreLion

3

En realidad, el uso de _mktemp_s() es una muy mala idea- sólo 26 posibles candidatos de nombre de archivo en cualquier contexto, y, con este rango limitado a ser atacado, se expone la condición de carrera muy mkstemp que() está diseñado para superar. Sin embargo, la otra solución propuesta, aunque mucho mejor, también es defectuosa, en la medida en que atribuye 62 grados de libertad en la elección de caracteres de nombre de archivo sustitutos, mientras que la insensibilidad de mayúsculas y minúsculas del sistema de archivos de Windows consume 26 de ellos, dejando solo 36 ; esto tiene el efecto de ponderar la probabilidad de seleccionar cualquier carácter alfabético lógicamente distinguible al doble que para un numérico.

Con esto en mente, he publicado un parche MinGW aquí: https://sourceforge.net/p/mingw/bugs/2003/

Si se aprueba, esto añadirá formalmente tanto mkstemp() y mkdtemp() para la distribución estándar de MinGW.

+1

Para el registro, MinGW.org ahora proporciona mkstemp() y mkdtemp(), en las versiones de la biblioteca de tiempo de ejecución de MinGW, mingwrt-3.21 y posterior, (pero no en las variantes mingwrt-4.x con fallas fatales, que ahora han sido retirado de la publicación general). –

+0

¿Tiene un enlace con respecto al retiro? Al mirar la sección de archivos de sourceforge, puedo ver que algunas versiones de mingwrt 4er están disponibles para [descargar] (https://sourceforge.net/projects/mingw/files/MinGW/Base/mingwrt/). – maxschlepzig