2011-06-06 92 views
2

在Windows 7上運行64位下面的代碼TMPFILE()在Windows 7 64位系統

#include <stdio.h> 
#include <errno.h> 

int main() { 
    int i; 
    FILE *tmp; 
    for (i = 0; i < 10000; i++) { 
     errno = 0; 
     if(!(tmp = tmpfile())) printf("Fail %d, err %d\n", i, errno); 
     fclose(tmp); 
    } 
    return 0; 
} 

給出錯誤號13(拒絕),在637和​​第一千零四調用,它適用於XP的罰款(沒有試過7 x86)。我錯過了什麼或者這是一個錯誤?

+0

您可能(但極不可能)您正在運行「TMP_MAX」。 C99標準規定:「應該可以在程序生命週期中至少打開'TMP_MAX'臨時文件」。在我的系統(Mac OS X)上,'TMP_MAX'是308915776(26^6),我很驚訝它在Windows上不會很大。 – 2011-06-06 02:18:42

回答

3

複習的從上tmpfile()手冊頁,它返回一個位一個FILE*

該文件將被自動當它被關閉或刪除該程序終止。

我對此問題的判決:在Windows上刪除文件很奇怪。

當您在Windows上刪除文件時,只要有東西存在句柄,您就不能在具有相同絕對路徑的東西上調用CreateFile,否則它將失敗,並顯示NT錯誤代碼STATUS_DELETE_PENDING, Win32代碼ERROR_ACCESS_DENIED。這可能是EPERMerrno的來源。您可以使用Sysinternals Process Monitor等工具來確認。

我的猜測是CRT以某種方式創建了一個與之前使用的名稱相同的文件。我有時親眼目睹,刪除Windows上的文件可能會出現異步,因爲某些其他進程(有時甚至是防病毒產品,對於剛剛關閉了刪除關閉句柄的事實......)會留下句柄打開文件,所以對於某個時間窗口,您將看到一個可見的文件,如果不觸及刪除掛起/訪問被拒絕,您將無法獲得句柄。或者,可能tmpfile只是簡單地選擇了其他進程正在處理的文件名。

爲了避免這種情況,您可能需要考慮另一種臨時文件的機制...例如,像Win32 GetTempFileName這樣的函數允許您創建自己的前綴,這可能會使碰撞的可能性降低。如果創建失敗時出現「已經存在」,那麼該函數似乎通過重試來解決競態條件,因此要小心刪除該事件生成的臨時文件名 - 刪除文件將取消您與其他進程/線程同時使用它的權限。

1

我在Windows 8上有類似的問題 - tmpfile()導致win32 ERROR_ACCESS_DENIED錯誤代碼 - 是的,如果你用管理員權限運行應用程序 - 那麼它工作正常。

我猜問題是在這裏提到: https://lists.gnu.org/archive/html/bug-gnulib/2007-02/msg00162.html

在Windows下,TMPFILE函數定義總是建立在根目錄 它的臨時文件。大多數用戶沒有 權限來執行此操作,所以它通常會失敗。

我懷疑這是有點不完整的Windows端口問題 - 所以這應該是一個錯誤報告給微軟。 (爲什麼要編碼tmpfile函數,如果它沒用?)

但誰有時間與微軟風車廠進行抗爭? :-)

我使用GetTempPathW/GetModuleFileNameW/_wfopen編碼了類似的實現。我遇到這個問題的代碼來自libjpeg - 我在這裏附上了整個源代碼,但是你可以從jpeg_open_backing_store中獲取代碼。

jmemwin.cpp: 

// 
// Windows port for jpeg lib functions. 
// 
#define JPEG_INTERNALS 
#include <Windows.h>  // GetTempFileName 
#undef FAR     // Will be redefined - disable warning 
#include "jinclude.h" 
#include "jpeglib.h" 

extern "C" { 
#include "jmemsys.h"  // jpeg_ api interface. 

// 
// Memory allocation and freeing are controlled by the regular library routines malloc() and free(). 
// 

GLOBAL(void *) jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) 
{ 
    return (void *) malloc(sizeofobject); 
} 

GLOBAL(void) jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) 
{ 
    free(object); 
} 

/* 
* "Large" objects are treated the same as "small" ones. 
* NB: although we include FAR keywords in the routine declarations, 
* this file won't actually work in 80x86 small/medium model; at least, 
* you probably won't be able to process useful-size images in only 64KB. 
*/ 

GLOBAL(void FAR *) jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) 
{ 
    return (void FAR *) malloc(sizeofobject); 
} 

GLOBAL(void) jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) 
{ 
    free(object); 
} 

// 
// Used only by command line applications, not by static library compilation 
// 
#ifndef DEFAULT_MAX_MEM  /* so can override from makefile */ 
#define DEFAULT_MAX_MEM  1000000L /* default: one megabyte */ 
#endif 

GLOBAL(long) jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, long max_bytes_needed, long already_allocated) 
{ 
    // jmemansi.c's jpeg_mem_available implementation was insufficient for some of .jpg loads. 
    MEMORYSTATUSEX status = { 0 }; 
    status.dwLength = sizeof(status); 
    GlobalMemoryStatusEx(&status); 

    if(status.ullAvailPhys > LONG_MAX) 
     // Normally goes here since new PC's have more than 4 Gb of ram. 
     return LONG_MAX; 

    return (long) status.ullAvailPhys; 
} 


/* 
    Backing store (temporary file) management. 
    Backing store objects are only used when the value returned by 
    jpeg_mem_available is less than the total space needed. You can dispense 
    with these routines if you have plenty of virtual memory; see jmemnobs.c. 
*/ 

METHODDEF(void) read_backing_store (j_common_ptr cinfo, backing_store_ptr info, void FAR * buffer_address, long file_offset, long byte_count) 
{ 
    if (fseek(info->temp_file, file_offset, SEEK_SET)) 
     ERREXIT(cinfo, JERR_TFILE_SEEK); 

    size_t readed = fread(buffer_address, 1, byte_count, info->temp_file); 

    if (readed != (size_t) byte_count) 
     ERREXIT(cinfo, JERR_TFILE_READ); 
} 


METHODDEF(void) 
write_backing_store (j_common_ptr cinfo, backing_store_ptr info, void FAR * buffer_address, long file_offset, long byte_count) 
{ 
    if (fseek(info->temp_file, file_offset, SEEK_SET)) 
     ERREXIT(cinfo, JERR_TFILE_SEEK); 

    if (JFWRITE(info->temp_file, buffer_address, byte_count) != (size_t) byte_count) 
     ERREXIT(cinfo, JERR_TFILE_WRITE); 

    // E.g. if you need to debug writes. 
    //if(fflush(info->temp_file) != 0) 
    // ERREXIT(cinfo, JERR_TFILE_WRITE); 
} 


METHODDEF(void) 
close_backing_store (j_common_ptr cinfo, backing_store_ptr info) 
{ 
    fclose(info->temp_file); 
    // File is deleted using 'D' flag on open. 
} 

static HMODULE DllHandle() 
{ 
    MEMORY_BASIC_INFORMATION info; 
    VirtualQuery(DllHandle, &info, sizeof(MEMORY_BASIC_INFORMATION)); 
    return (HMODULE)info.AllocationBase; 
} 

GLOBAL(void) jpeg_open_backing_store(j_common_ptr cinfo, backing_store_ptr info, long total_bytes_needed) 
{ 
    // Generate unique filename. 
    wchar_t path[ MAX_PATH ] = { 0 }; 
    wchar_t dllPath[ MAX_PATH ] = { 0 }; 
    GetTempPathW(MAX_PATH, path); 

    // Based on .exe or .dll filename 
    GetModuleFileNameW(DllHandle(), dllPath, MAX_PATH); 

    wchar_t* p = wcsrchr(dllPath, L'\\'); 
    wchar_t* ext = wcsrchr(p + 1, L'.'); 

    if(ext) *ext = 0; 
    wchar_t* outFile = path + wcslen(path); 

    static int iTempFileId = 1; 
    // Based on process id (so processes would not fight with each other) 
    // Based on some process global id. 
    wsprintfW(outFile, L"%s_%d_%d.tmp",p + 1, GetCurrentProcessId(), iTempFileId++); 

    // 'D' - temporary file. 
    if ((info->temp_file = _wfopen(path, L"w+bD")) == NULL) 
     ERREXITS(cinfo, JERR_TFILE_CREATE, ""); 

    info->read_backing_store = read_backing_store; 
    info->write_backing_store = write_backing_store; 
    info->close_backing_store = close_backing_store; 
} //jpeg_open_backing_store 


/* 
* These routines take care of any system-dependent initialization and 
* cleanup required. 
*/ 

GLOBAL(long) 
jpeg_mem_init (j_common_ptr cinfo) 
{ 
    return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ 
} 

GLOBAL(void) 
jpeg_mem_term (j_common_ptr cinfo) 
{ 
    /* no work */ 
} 

} 

我故意忽略了錯誤的一些功能 - 你見過GetTempPathW或GetModuleFileNameW失敗?