2011-05-17 33 views
7

可有人點我在Win32上實現代碼mkstemp()(C/C++),或非常接近的模擬。mkstemp()實現爲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) { 
    ... 
} 

感謝

回答

4

您可以使用它從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[] = 
"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; 
} 

O_EXCL定義爲;

#define _O_EXCL   0x0400 
#define O_EXCL   _O_EXCL 

你可以輕鬆地將mkstemp支持從其中解脫出來。

+0

@Ismail,謝謝,賓果。而已。 – Andrei 2011-05-17 20:28:19

+1

@Andrei,請注意這個提議實現中的缺陷:它錯誤地將62個自由度歸因於文件名字符的選擇,實際上只存在36個; (大小寫字母在MS-Windows文件名中無法區分)。此外,Windows具有更好的API來生成密碼安全的隨機數字序列,而不是像這裏所示的技術。 – 2015-05-01 07:51:52

+0

正如代碼片段的頂部所述,這個實現(包括代碼註釋)取自glibc,特別是'sysdeps/posix/tempname.c'中的'__gen_tempname'。正如@KeithMarshall指出的那樣,它轉換到Windows是不完整的,可能會有更多的陷阱...... – josch 2018-01-19 06:35:13

-1

可以使用_mktemp_s()功能,或者它的任何變化的:

errno_t _mktemp_s(
    char *template, 
    size_t sizeInChars 
); 

其中:

  • 模板:文件名模式。
  • sizeInChars:在_mktemp_s在單字節字符的緩衝區的大小;在_wmktemp_s中包含空終止符。

它返回0成功,並且在失敗時的錯誤代碼。請注意,該功能修改template參數。

+1

使用'_mktemp_s()'肯定比重新發明輪子更好。但請注意,與POSIX的'mkstemp()'不同,它不會打開文件或返回fd ***。它只是返回一個文件名字符串,你必須自己打開它。 – MestreLion 2012-10-10 07:25:43

3

其實用_mktemp_s()是一個非常糟糕的主意 - 在任何一個方面只有26種可能的文件名候選人,並與被攻擊這個有限的範圍,它暴露了mkstemp非常競態條件()旨在克服。然而,另一個提出的解決方案雖然好得多,但也存在缺陷,因爲它在替代文件名字符的選擇方面擁有62個自由度,而Windows文件系統的不區分大小寫則消耗了26個,因此只剩下36個;這具有在加權兩倍於數字選擇任何邏輯上可區分的字母字符的概率的效果。

考慮到這一點,我在這裏發表MinGW的補丁: https://sourceforge.net/p/mingw/bugs/2003/

如果獲得通過,這將正式既mkstemp()和mkdtemp()添加到標準MinGW的分佈。

+1

爲了記錄,MinGW.org現在在MinGW運行時庫mingwrt-3.21及更高版本的發行版中提供mkstemp()和mkdtemp()(但不包含致命缺陷的mingwrt-4.x變體,現在已經從普通版本撤回)。 – 2015-03-02 04:03:49

+0

您有關於退款的鏈接嗎?查看sourceforge文件部分,我可以看到一些mingwrt 4er版本可用於[下載](https://sourceforge.net/projects/mingw/files/MinGW/Base/mingwrt/)。 – maxschlepzig 2016-02-24 22:26:22