2011-06-06 93 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失败?