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
This commit is contained in:
nhmall
2020-09-22 09:03:15 -04:00
parent cf482f1f42
commit 1a0ee44760
3 changed files with 99 additions and 18 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}