From: nhmall Date: Tue, 22 Sep 2020 13:03:15 +0000 (-0400) Subject: unique temp files for makedefs invocations (GitHub issue #391) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1a0ee44760c4353128da223a83319cc0bcb97047;p=nethack unique temp files for makedefs invocations (GitHub issue #391) As reported in https://github.com/NetHack/NetHack/issues/391 if make was invoked with -j, makedefs instances could end up running in parallel and could trample on each other's grep.tmp tempory files. Default to using mkstemp(); allow a port runtime library implementation that lacks mkstemp() to define HAS_NO_MKSTEMP to revert to the old behaviour. Provide a work-alike mkstemp() implementation for windows Visual Studio build in mdlib.c so there is no requirement to define HAS_NO_MKSTEMP there. Fixes #391 --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 5329e9833..96d26a53d 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -254,6 +254,12 @@ handle being interrupted by approaching monsters more consistently if hero attacked a peaceful monster, some other peaceful monsters with humanoid shape (minotaur, zruty, perhaps others) that witnessed it but which shouldn't be capable of normal speech expressed their surprise audibly +when make was invoked with -j makedefs instances could end up running in + parallel and could trample on each other's temp files; default to + using mkstemp(); allow a port runtime library implementation that lacks + mkstemp() to define HAS_NO_MKSTEMP to revert to the old behaviour; + provide a work-alike mkstemp() implementation for windows visual studio + in mdlib.c so there is no requirement to define HAS_NO_MKSTEMP there Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/mdlib.c b/src/mdlib.c index 59b94b459..79a748710 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -66,7 +66,14 @@ static char *FDECL(eos, (char *)); #if 0 static char *FDECL(mdlib_strsubst, (char *, const char *, const char *)); #endif + +#ifndef HAS_NO_MKSTEMP +#ifdef _MSC_VER +static int FDECL(mkstemp, (char *)); +#endif +#endif #endif /* MAKEDEFS_C || FOR_RUNTIME */ + #if !defined(MAKEDEFS_C) && defined(WIN32) extern int GUILaunched; #endif @@ -319,6 +326,23 @@ const char *build_date; return outbuf; } +#ifndef HAS_NO_MKSTEMP +#ifdef _MSC_VER +int +mkstemp(template) +char *template; +{ + int err; + + err = _mktemp_s(template, strlen(template) + 1); + if( err != 0 ) + return -1; + return _open(template, + _O_RDWR | _O_BINARY | _O_TEMPORARY | _O_CREAT, + _S_IREAD | _S_IWRITE); +} +#endif /* _MSC_VER */ +#endif /* HAS_NO_MKSTEMP */ #endif /* MAKEDEFS_C || FOR_RUNTIME */ static int diff --git a/util/makedefs.c b/util/makedefs.c index 8b5179c1b..0cf4b09e3 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -124,6 +124,7 @@ static struct version_info version; /* Use this as an out-of-bound value in the close table. */ #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */ #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */ +#define FLG_TEMPFILE 0x01 /* flag for temp file */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #ifdef VISION_TABLES @@ -165,7 +166,7 @@ extern void NDECL(objects_globals_init); /* objects.c */ static char *FDECL(name_file, (const char *, const char *)); static void FDECL(delete_file, (const char *template, const char *)); -static FILE *FDECL(getfp, (const char *, const char *, const char *)); +static FILE *FDECL(getfp, (const char *, const char *, const char *, int)); static void FDECL(do_ext_makedefs, (int, char **)); static char *FDECL(xcrypt, (const char *)); static unsigned long FDECL(read_rumors_file, @@ -393,17 +394,40 @@ const char *tag; } static FILE * -getfp(template, tag, mode) +getfp(template, tag, mode, flg) const char *template; const char *tag; const char *mode; +#ifndef HAS_NO_MKSTEMP +int flg; +#else +int flg UNUSED; +#endif { char *name = name_file(template, tag); - FILE *rv = fopen(name, mode); + FILE *rv = (FILE *) 0; +#ifndef HAS_NO_MKSTEMP + boolean istemp = (flg & FLG_TEMPFILE) != 0; + char tmpfbuf[MAXFNAMELEN]; + int tmpfd; +#endif +#ifndef HAS_NO_MKSTEMP + if (istemp) { + (void) snprintf(tmpfbuf, sizeof tmpfbuf, DATA_TEMPLATE, "mdXXXXXX"); + tmpfd = mkstemp(tmpfbuf); + if (tmpfd >= 0) + rv = fdopen(tmpfd, WRTMODE); /* temp file is always read+write */ + } else +#endif + rv = fopen(name, mode); if (!rv) { - Fprintf(stderr, "Can't open '%s'.\n", name); - exit(EXIT_FAILURE); + Fprintf(stderr, "Can't open '%s'.\n", +#ifndef HAS_NO_MKSTEMP + istemp ? tmpfbuf : +#endif + name); + exit(EXIT_FAILURE); } return rv; } @@ -426,7 +450,7 @@ static int FDECL(grep_check_id, (const char *)); static void FDECL(grep_show_wstack, (const char *)); static char *FDECL(do_grep_control, (char *)); static void NDECL(do_grep); -static void FDECL(grep0, (FILE *, FILE *)); +static void FDECL(grep0, (FILE *, FILE *, int)); static int grep_trace = 0; @@ -775,7 +799,7 @@ char *buf; } #endif -static void grep0(FILE *, FILE *); +static void grep0(FILE *, FILE *, int); static void do_grep() @@ -790,14 +814,26 @@ do_grep() exit(EXIT_FAILURE); } - grep0(inputfp, outputfp); + grep0(inputfp, outputfp, 0); } static void -grep0(inputfp0, outputfp0) +grep0(inputfp0, outputfp0, flg) FILE *inputfp0; FILE *outputfp0; +#ifndef HAS_NO_MKSTEMP +int flg; +#else +int flg UNUSED; +#endif { +#ifndef HAS_NO_MKSTEMP + /* if grep0 is passed FLG_TEMPFILE flag, it will + leave the output file open when it returns. + The caller will have to take care of calling + fclose() when it is done with the file */ + boolean istemp = (flg & FLG_TEMPFILE) != 0; +#endif char buf[16384]; /* looong, just in case */ while (!feof(inputfp0) && !ferror(inputfp0)) { @@ -837,7 +873,12 @@ FILE *outputfp0; exit(EXIT_FAILURE); } fclose(inputfp0); - fclose(outputfp0); +#ifndef HAS_NO_MKSTEMP + if (istemp) + rewind(outputfp0); + else +#endif + fclose(outputfp0); if (grep_sp) { Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp, grep_sp == 1 ? "" : "s"); @@ -967,10 +1008,13 @@ const char *deflt_content; more likely to be picked than normal but it's nothing to worry about */ (void) fputs(xcrypt(deflt_content), ofp); - tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); - grep0(ifp, tfp); - ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); - + tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE, FLG_TEMPFILE); + grep0(ifp, tfp, FLG_TEMPFILE); +#ifndef HAS_NO_MKSTEMP + ifp = tfp; +#else + ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE, 0); +#endif while ((line = fgetline(ifp)) != 0) { if (line[0] != '#' && line[0] != '\n') (void) fputs(xcrypt(line), ofp); @@ -979,7 +1023,9 @@ const char *deflt_content; Fclose(ifp); Fclose(ofp); +#ifdef HAS_NO_MKSTEMP delete_file(DATA_TEMPLATE, "grep.tmp"); +#endif return; } @@ -1747,10 +1793,13 @@ do_dungeon() } Fprintf(ofp, "%s", Dont_Edit_Data); - tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); - grep0(ifp, tfp); - ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); - + tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE, FLG_TEMPFILE); + grep0(ifp, tfp, FLG_TEMPFILE); +#ifndef HAS_NO_MKSTEMP + ifp = tfp; +#else + ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE, 0); +#endif while ((line = fgetline(ifp)) != 0) { SpinCursor(3); @@ -1764,7 +1813,9 @@ do_dungeon() Fclose(ifp); Fclose(ofp); +#ifdef HAS_NO_MKSTEMP delete_file(DATA_TEMPLATE, "grep.tmp"); +#endif return; }