From 7c162c1b5bd352202ab2a28d2d1b5cf804960150 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 21 Jun 2021 13:45:20 +0000 Subject: [PATCH] Try to get windows to delete temporary files early, so they don't linger over crashes or whatever. win9x still sucks. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5898 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/common/fs_stdio.c | 5 +-- engine/common/fs_win32.c | 70 ++++++++++++++++++++++++++++++++++++++++ engine/common/fs_xz.c | 27 +++++++++++----- 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index 97143c59..4affdd6c 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -2,7 +2,7 @@ #include "fs.h" #include "errno.h" -#if !defined(NACL) && !defined(FTE_TARGET_WEB) +#if !defined(NACL) && !defined(FTE_TARGET_WEB) && !defined(_WIN32) #ifdef WEBSVONLY #define Z_Free free @@ -120,7 +120,8 @@ vfsfile_t *FSSTDIO_OpenTemp(void) vfsstdiofile_t *file; #ifdef _WIN32 - /*warning: annother app might manage to open the file before we can. if the file is not opened exclusively then we can end up with issues + /*microsoft's tmpfile will nearly always fail, as it insists on writing to the root directory and that requires running everything with full admin rights. + warning: there's a race condition between tempnam and fopen. if the file is not opened exclusively then we can end up with issues on windows, fopen is typically exclusive anyway, but not on unix. but on unix, tmpfile is actually usable, so special-case the windows code we also have a special close function to ensure the file is deleted too */ diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index a1f1648f..97c702d2 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -201,6 +201,7 @@ void MyRegDeleteKeyValue(void *base, const char *keyname, const char *valuename) #define VFSW32_Open VFSOS_Open #define VFSW32_OpenPath VFSOS_OpenPath +#define VFSW32_OpenTemp FS_OpenTemp typedef struct { searchpathfuncs_t pub; @@ -314,6 +315,75 @@ static qboolean QDECL VFSW32_Close(vfsfile_t *file) Z_Free(file); return true; } +static qboolean QDECL VFSW32_CloseTemp(vfsfile_t *file) +{ + vfsw32file_t *intfile = (vfsw32file_t*)file; + if (intfile->mmap) + { + UnmapViewOfFile(intfile->mmap); + CloseHandle(intfile->mmh); + } + CloseHandle(intfile->hand); + DeleteFileA((char*)(intfile+1)); + Z_Free(file); + return true; +} + +vfsfile_t *QDECL VFSW32_OpenTemp(void) +{ + static int seq=-1; + HANDLE h = INVALID_HANDLE_VALUE; + vfsw32file_t *file; + if (WinNT) + { //gotta use wide stuff. + //on the plus side, FILE_SHARE_DELETE works. + wchar_t osname[MAX_PATH]; + wchar_t tmppath[MAX_PATH]; + if (GetTempPathW(countof(tmppath), tmppath)) + if ((seq=GetTempFileNameW(tmppath, L"fte", ++seq, osname))) + h = CreateFileW(osname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL); + if (!h) + return VFSPIPE_Open(1, true); + DeleteFileW(osname); + + file = Z_Malloc(sizeof(vfsw32file_t)); +#ifdef _DEBUG + narrowen(file->funcs.dbgname, sizeof(file->funcs.dbgname), osname); +#endif + file->funcs.Close = VFSW32_Close; //we already deleted it. woo. + } + else + { //can't use wide stuff. + //FLIE_SHARE_DELETE doesn't work. we have to faff around ourselves. + char osname[MAX_PATH]; + char tmppath[MAX_PATH]; + if (GetTempPathA(countof(tmppath), tmppath)) + if ((seq=GetTempFileNameA(tmppath, "fte", ++seq, osname))) + h = CreateFileA(osname, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); + if (!h) + return VFSPIPE_Open(1, true); + + file = Z_Malloc(sizeof(vfsw32file_t) + strlen(osname)+1); + strcpy((char*)(file+1), osname); +#ifdef _DEBUG + narrowen(file->funcs.dbgname, sizeof(file->funcs.dbgname), osname); +#endif + file->funcs.Close = VFSW32_CloseTemp; //gotta delete it after close. hopefully we won't crash too often... + } + file->funcs.ReadBytes = VFSW32_ReadBytes; + file->funcs.WriteBytes = VFSW32_WriteBytes; + file->funcs.Seek = VFSW32_Seek; + file->funcs.Tell = VFSW32_Tell; + file->funcs.GetLen = VFSW32_GetSize; + file->funcs.Flush = VFSW32_Flush; + file->hand = h; + file->mmh = INVALID_HANDLE_VALUE; + file->mmap = NULL; + file->offset = 0; + file->length = 0; + + return &file->funcs; +} //WARNING: handle can be null static vfsfile_t *QDECL VFSW32_OpenInternal(vfsw32path_t *handle, const char *quakename, const char *osname, const char *mode) diff --git a/engine/common/fs_xz.c b/engine/common/fs_xz.c index 39b00a69..b8727d18 100644 --- a/engine/common/fs_xz.c +++ b/engine/common/fs_xz.c @@ -2994,13 +2994,19 @@ typedef struct struct xz_dec *s; } vf_xz_dec_t; -static qboolean QDECL FS_XZ_Dec_Close(vfsfile_t *f) +static vfsfile_t *FS_XZ_Finish(vfsfile_t *f) { vf_xz_dec_t *n = (vf_xz_dec_t*)f; - VFS_CLOSE(n->outfile); + vfsfile_t *r = n->outfile; if (n->s) xz_dec_end(n->s); Z_Free(n); + return r; +} +static qboolean QDECL FS_XZ_Dec_Close(vfsfile_t *f) +{ + vfsfile_t *orig = FS_XZ_Finish(f); + VFS_CLOSE(orig); return true; } static int QDECL FS_XZ_Dec_Write(vfsfile_t *f, const void *buffer, int len) @@ -3126,21 +3132,26 @@ vfsfile_t *FS_XZ_DecompressReadFilter(vfsfile_t *srcfile) if (blocksize == HEADER_MAGIC_SIZE && !memcmp(block, HEADER_MAGIC, HEADER_MAGIC_SIZE)) { //okay, looks like an xz. - vfsfile_t *pipe = VFSPIPE_Open(2, false); - vfsfile_t *xzpipe = FS_XZ_DecompressWriteFilter(pipe); + vfsfile_t *xzpipe = FS_OpenTemp(); + if (!xzpipe) + xzpipe = VFSPIPE_Open(1, true); + xzpipe = FS_XZ_DecompressWriteFilter(xzpipe); for (;blocksize;) { if (blocksize < 0 || blocksize != VFS_WRITE(xzpipe, block, blocksize)) { - VFS_CLOSE(pipe); - pipe = NULL; + VFS_CLOSE(xzpipe); + xzpipe = NULL; break; } blocksize = VFS_READ(srcfile, block, sizeof(block)); } VFS_CLOSE(srcfile); - VFS_CLOSE(xzpipe); - return pipe; + + if (xzpipe) + xzpipe = FS_XZ_Finish(xzpipe); + VFS_SEEK(xzpipe, 0); + return xzpipe; } VFS_SEEK(srcfile, 0); return srcfile;