Function tmpfile() in msvcr100 and older versions (including the system os
msvcrt.dll) is trying to create a temporary file in the root of the drive
corresponding to current working directory. In most cases is the current
working directory in some user profile application directory, which means
that the directory for temporary file used by the tmpfile() is often C:\.
Writing to the C:\ is not allowed by unprivileged processes on Windows
Vista and new systems, so tmpfile() is not working at all.

This tmpfile() problem was fixed in msvcr110.dll (and hence also in UCRT)
and tmpfile() in these new versions is creating a temporary file in the
temporary directory returned by WinAPI function GetTempPath() instead of
the root directory.

For affected msvcrt import libraries, replace the msvcrt version of
tmpfile() function by mingw-w64 emulation which attempts to create a
temporary file in GetTempPath() too. For generating unique filename is used
the tmpnam() function together with open(O_CREAT | O_EXCL) in a loop to
prevent race condition in case two different processes or threads generate
same temporary name by the tmpnam() function.

Seems that tmpnam() function generates same file name pattern as the
tmpfile() function. So with this change, the file name should be same, just
located in the proper temporary directory.

Bug: https://sourceforge.net/p/mingw-w64/bugs/921/
---
 mingw-w64-crt/Makefile.am                    |  6 +-
 mingw-w64-crt/def-include/crt-aliases.def.in |  2 +
 mingw-w64-crt/lib-common/msvcrt.def.in       |  3 +-
 mingw-w64-crt/lib32/crtdll.def.in            |  3 +-
 mingw-w64-crt/lib32/msvcr100.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcr100d.def.in         |  3 +-
 mingw-w64-crt/lib32/msvcr40d.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcr70.def.in           |  3 +-
 mingw-w64-crt/lib32/msvcr70d.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcr71.def.in           |  3 +-
 mingw-w64-crt/lib32/msvcr71d.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcr80.def.in           |  3 +-
 mingw-w64-crt/lib32/msvcr80d.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcr90.def.in           |  3 +-
 mingw-w64-crt/lib32/msvcr90d.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcrt10.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcrt20.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcrt40.def.in          |  3 +-
 mingw-w64-crt/lib32/msvcrtd.def.in           |  3 +-
 mingw-w64-crt/lib64/msvcr100.def.in          |  3 +-
 mingw-w64-crt/lib64/msvcr100d.def.in         |  3 +-
 mingw-w64-crt/lib64/msvcr80.def.in           |  3 +-
 mingw-w64-crt/lib64/msvcr80d.def.in          |  3 +-
 mingw-w64-crt/lib64/msvcr90.def.in           |  3 +-
 mingw-w64-crt/lib64/msvcr90d.def.in          |  3 +-
 mingw-w64-crt/stdio/tmpfile.c                | 71 ++++++++++++++++++++
 mingw-w64-crt/testcases/Makefile.am          |  1 +
 mingw-w64-crt/testcases/t_lfs.c              |  4 +-
 mingw-w64-crt/testcases/t_tmpfile.c          | 21 ++++++
 29 files changed, 148 insertions(+), 26 deletions(-)
 create mode 100644 mingw-w64-crt/stdio/tmpfile.c
 create mode 100644 mingw-w64-crt/testcases/t_tmpfile.c

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index acb5f5fb2779..00541664aaa2 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -373,7 +373,8 @@ src_msvcrt=\
   stdio/msvcr110pre_stat32.c \
   stdio/msvcr110pre_stat64i32.c \
   stdio/msvcr110pre_wstat32.c \
-  stdio/msvcr110pre_wstat64i32.c
+  stdio/msvcr110pre_wstat64i32.c \
+  stdio/tmpfile.c
 
 src_msvcrt_add_x86=\
   secapi/_access_s.c \
@@ -960,7 +961,8 @@ src_pre_msvcr110=\
   stdio/msvcr110pre_stat32.c \
   stdio/msvcr110pre_stat64i32.c \
   stdio/msvcr110pre_wstat32.c \
-  stdio/msvcr110pre_wstat64i32.c
+  stdio/msvcr110pre_wstat64i32.c \
+  stdio/tmpfile.c
 
 src_pre_msvcr120=\
   $(src_msvcrt_add_vscanf) \
diff --git a/mingw-w64-crt/def-include/crt-aliases.def.in 
b/mingw-w64-crt/def-include/crt-aliases.def.in
index c1534fa6660a..8f9ee2e09c46 100644
--- a/mingw-w64-crt/def-include/crt-aliases.def.in
+++ b/mingw-w64-crt/def-include/crt-aliases.def.in
@@ -295,7 +295,9 @@ creat64 == _creat
 open64 == _open
 fopen64 == fopen
 freopen64 == freopen
+#ifndef NO_TMPFILE_ALIAS
 tmpfile64 == tmpfile
+#endif
 #ifndef NO_FPOS64_ALIASES
 ; fgetpos and fsetpos are already 64-bit
 fgetpos64 == fgetpos
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in 
b/mingw-w64-crt/lib-common/msvcrt.def.in
index e597adad5efe..7b76e52054c1 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -1089,7 +1089,7 @@ system
 tan
 tanh ; if we implement tanh, we can set it to DATA only.
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -1912,6 +1912,7 @@ F_I386(_libm_sse2_tan_precise)
 #define NO_FSTAT64_ALIAS
 #endif
 #define NO_TIME_ALIAS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #ifdef __i386__
diff --git a/mingw-w64-crt/lib32/crtdll.def.in 
b/mingw-w64-crt/lib32/crtdll.def.in
index 3e3d80421150..72b2b87a7b77 100644
--- a/mingw-w64-crt/lib32/crtdll.def.in
+++ b/mingw-w64-crt/lib32/crtdll.def.in
@@ -577,7 +577,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -628,6 +628,7 @@ _ultow
 #define NO_WIDE_FIXED_SIZE
 #define NO_I64_FIXED_SIZE
 #define NO_FPOS64_ALIASES
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_GET_PUT_WCHAR_ALIASES
diff --git a/mingw-w64-crt/lib32/msvcr100.def.in 
b/mingw-w64-crt/lib32/msvcr100.def.in
index b8f183bf0e11..a0a3b685dc10 100644
--- a/mingw-w64-crt/lib32/msvcr100.def.in
+++ b/mingw-w64-crt/lib32/msvcr100.def.in
@@ -1839,7 +1839,7 @@ system
 tan
 ; If we implement tanh, we can set it to DATA only.
 tanh
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary 
directory_s
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1902,6 +1902,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcr100d.def.in 
b/mingw-w64-crt/lib32/msvcr100d.def.in
index 7dad2cc0f0be..3af607aaec0a 100644
--- a/mingw-w64-crt/lib32/msvcr100d.def.in
+++ b/mingw-w64-crt/lib32/msvcr100d.def.in
@@ -1902,7 +1902,7 @@ swscanf_s
 system
 tan
 tanh
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1965,6 +1965,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcr40d.def.in 
b/mingw-w64-crt/lib32/msvcr40d.def.in
index 1590e659077b..105e5e960f58 100644
--- a/mingw-w64-crt/lib32/msvcr40d.def.in
+++ b/mingw-w64-crt/lib32/msvcr40d.def.in
@@ -1611,7 +1611,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -1696,6 +1696,7 @@ _dstbias DATA
 
 ; Include symbol aliases for compatibility with msvcrt.dll
 #define FIXED_SIZE_SYMBOLS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_IOB_FUNC_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcr70.def.in 
b/mingw-w64-crt/lib32/msvcr70.def.in
index ec64df727c37..60f20cd83022 100644
--- a/mingw-w64-crt/lib32/msvcr70.def.in
+++ b/mingw-w64-crt/lib32/msvcr70.def.in
@@ -861,7 +861,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -902,6 +902,7 @@ wscanf
 
 #define FIXED_SIZE_SYMBOLS
 #define NO_FIXED_SIZE_64_ALIAS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_TZ_ALIASES
diff --git a/mingw-w64-crt/lib32/msvcr70d.def.in 
b/mingw-w64-crt/lib32/msvcr70d.def.in
index 408f1e9194ce..b221c4b10c6f 100644
--- a/mingw-w64-crt/lib32/msvcr70d.def.in
+++ b/mingw-w64-crt/lib32/msvcr70d.def.in
@@ -905,7 +905,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -946,6 +946,7 @@ wscanf
 
 #define FIXED_SIZE_SYMBOLS
 #define NO_FIXED_SIZE_64_ALIAS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_TZ_ALIASES
diff --git a/mingw-w64-crt/lib32/msvcr71.def.in 
b/mingw-w64-crt/lib32/msvcr71.def.in
index 6e3f54069999..319c0c55806c 100644
--- a/mingw-w64-crt/lib32/msvcr71.def.in
+++ b/mingw-w64-crt/lib32/msvcr71.def.in
@@ -855,7 +855,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -896,6 +896,7 @@ wscanf
 
 #define FIXED_SIZE_SYMBOLS
 #define NO_FIXED_SIZE_64_ALIAS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_TZ_ALIASES
diff --git a/mingw-w64-crt/lib32/msvcr71d.def.in 
b/mingw-w64-crt/lib32/msvcr71d.def.in
index 7f70c52095a2..62ad4b2c2e64 100644
--- a/mingw-w64-crt/lib32/msvcr71d.def.in
+++ b/mingw-w64-crt/lib32/msvcr71d.def.in
@@ -899,7 +899,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -940,6 +940,7 @@ wscanf
 
 #define FIXED_SIZE_SYMBOLS
 #define NO_FIXED_SIZE_64_ALIAS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_TZ_ALIASES
diff --git a/mingw-w64-crt/lib32/msvcr80.def.in 
b/mingw-w64-crt/lib32/msvcr80.def.in
index 96116ac33248..80cb49536766 100644
--- a/mingw-w64-crt/lib32/msvcr80.def.in
+++ b/mingw-w64-crt/lib32/msvcr80.def.in
@@ -1473,7 +1473,7 @@ swscanf_s
 system
 tan
 tanh ; If we implement tanh, we can set it to DATA only.
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1547,6 +1547,7 @@ _fread_nolock_s
 fread_s
 
 ; Include symbol aliases for compatibility with msvcrt.dll
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcr80d.def.in 
b/mingw-w64-crt/lib32/msvcr80d.def.in
index c34f7a55152d..7b7b17ba7838 100644
--- a/mingw-w64-crt/lib32/msvcr80d.def.in
+++ b/mingw-w64-crt/lib32/msvcr80d.def.in
@@ -1556,7 +1556,7 @@ swscanf_s
 system
 tan
 tanh
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1625,6 +1625,7 @@ _fread_nolock_s
 fread_s
 
 ; Include symbol aliases for compatibility with msvcrt.dll
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcr90.def.in 
b/mingw-w64-crt/lib32/msvcr90.def.in
index aba9b9726b6b..f75d1693787b 100644
--- a/mingw-w64-crt/lib32/msvcr90.def.in
+++ b/mingw-w64-crt/lib32/msvcr90.def.in
@@ -1471,7 +1471,7 @@ system
 tan
 ; If we have tanh implementation, we can set it to DATA only too.
 tanh
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1532,6 +1532,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcr90d.def.in 
b/mingw-w64-crt/lib32/msvcr90d.def.in
index 2c04ccd82d1e..0d43a92cba7f 100644
--- a/mingw-w64-crt/lib32/msvcr90d.def.in
+++ b/mingw-w64-crt/lib32/msvcr90d.def.in
@@ -1543,7 +1543,7 @@ system
 tan
 ; If we implement tanh too, we can set it to DATA only.
 tanh
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1604,6 +1604,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcrt10.def.in 
b/mingw-w64-crt/lib32/msvcrt10.def.in
index 9d4db9f811e7..1f139e7880f0 100644
--- a/mingw-w64-crt/lib32/msvcrt10.def.in
+++ b/mingw-w64-crt/lib32/msvcrt10.def.in
@@ -1255,7 +1255,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -1298,6 +1298,7 @@ wscanf
 #define NO_WIDE_FIXED_SIZE
 #define NO_I64_FIXED_SIZE
 #define NO_FPOS64_ALIASES
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_GET_PUT_WCHAR_ALIASES
diff --git a/mingw-w64-crt/lib32/msvcrt20.def.in 
b/mingw-w64-crt/lib32/msvcrt20.def.in
index 94dcdb2fab49..3ecdb4c88858 100644
--- a/mingw-w64-crt/lib32/msvcrt20.def.in
+++ b/mingw-w64-crt/lib32/msvcrt20.def.in
@@ -1479,7 +1479,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -1579,6 +1579,7 @@ _safe_fprem1
 #define FIXED_SIZE_SYMBOLS
 #define NO_I64_FIXED_SIZE
 #define NO_FPOS64_ALIASES
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define NO_DSTBIAS
 #define WITH_NEXTAFTER_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcrt40.def.in 
b/mingw-w64-crt/lib32/msvcrt40.def.in
index a061b15a8a65..fdeb7175ccd5 100644
--- a/mingw-w64-crt/lib32/msvcrt40.def.in
+++ b/mingw-w64-crt/lib32/msvcrt40.def.in
@@ -1579,7 +1579,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -1661,6 +1661,7 @@ _dstbias DATA
 
 ; Include symbol aliases for compatibility with msvcrt.dll
 #define FIXED_SIZE_SYMBOLS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_IOB_FUNC_ALIAS
diff --git a/mingw-w64-crt/lib32/msvcrtd.def.in 
b/mingw-w64-crt/lib32/msvcrtd.def.in
index 36e9fa45eda0..2628b1848b4d 100644
--- a/mingw-w64-crt/lib32/msvcrtd.def.in
+++ b/mingw-w64-crt/lib32/msvcrtd.def.in
@@ -805,7 +805,7 @@ system
 tan
 tanh
 time
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpnam
 tolower
 toupper
@@ -854,6 +854,7 @@ __unDNameEx
 _chkesp
 
 #define FIXED_SIZE_SYMBOLS
+#define NO_TMPFILE_ALIAS
 #define NO_STRCMPI_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_IOB_FUNC_ALIAS
diff --git a/mingw-w64-crt/lib64/msvcr100.def.in 
b/mingw-w64-crt/lib64/msvcr100.def.in
index 0b378d9f1ac2..2afc8e91ccc3 100644
--- a/mingw-w64-crt/lib64/msvcr100.def.in
+++ b/mingw-w64-crt/lib64/msvcr100.def.in
@@ -1801,7 +1801,7 @@ tan
 tanf DATA
 tanh
 tanhf DATA
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1864,6 +1864,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib64/msvcr100d.def.in 
b/mingw-w64-crt/lib64/msvcr100d.def.in
index 138a161d8c23..c316cdf4f615 100644
--- a/mingw-w64-crt/lib64/msvcr100d.def.in
+++ b/mingw-w64-crt/lib64/msvcr100d.def.in
@@ -1866,7 +1866,7 @@ tan
 tanf DATA ; overwritten
 tanh
 tanhf DATA ; overwritten
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1929,6 +1929,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib64/msvcr80.def.in 
b/mingw-w64-crt/lib64/msvcr80.def.in
index b3787ba7d9af..ddfcf10d3c4b 100644
--- a/mingw-w64-crt/lib64/msvcr80.def.in
+++ b/mingw-w64-crt/lib64/msvcr80.def.in
@@ -1421,7 +1421,7 @@ tan
 tanf
 tanh
 tanhf
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1495,6 +1495,7 @@ _fread_nolock_s
 fread_s
 
 ; Include symbol aliases for compatibility with msvcrt.dll
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib64/msvcr80d.def.in 
b/mingw-w64-crt/lib64/msvcr80d.def.in
index e30a100d5cab..d9ad7c87c3ba 100644
--- a/mingw-w64-crt/lib64/msvcr80d.def.in
+++ b/mingw-w64-crt/lib64/msvcr80d.def.in
@@ -1498,7 +1498,7 @@ tan
 tanf
 tanh
 tanhf
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1567,6 +1567,7 @@ _fread_nolock_s
 fread_s
 
 ; Include symbol aliases for compatibility with msvcrt.dll
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib64/msvcr90.def.in 
b/mingw-w64-crt/lib64/msvcr90.def.in
index ea71960598b1..0af24dae8921 100644
--- a/mingw-w64-crt/lib64/msvcr90.def.in
+++ b/mingw-w64-crt/lib64/msvcr90.def.in
@@ -1419,7 +1419,7 @@ tan
 tanf DATA
 tanh
 tanhf DATA
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1480,6 +1480,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/lib64/msvcr90d.def.in 
b/mingw-w64-crt/lib64/msvcr90d.def.in
index 01d12ceaaa41..451f21c1ec04 100644
--- a/mingw-w64-crt/lib64/msvcr90d.def.in
+++ b/mingw-w64-crt/lib64/msvcr90d.def.in
@@ -1485,7 +1485,7 @@ tan
 tanf
 tanh
 tanhf
-tmpfile
+; tmpfile replaced by emu, CRT version may not use writable temporary directory
 tmpfile_s
 tmpnam
 tmpnam_s
@@ -1546,6 +1546,7 @@ wprintf_s
 wscanf
 wscanf_s
 
+#define NO_TMPFILE_ALIAS
 #define WITH_NEXTAFTER_ALIAS
 #define WITH_ATOLL_ALIAS
 #define WITH_ATOLL_L_ALIAS
diff --git a/mingw-w64-crt/stdio/tmpfile.c b/mingw-w64-crt/stdio/tmpfile.c
new file mode 100644
index 000000000000..f0c77f52a18a
--- /dev/null
+++ b/mingw-w64-crt/stdio/tmpfile.c
@@ -0,0 +1,71 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <io.h>
+#include <windows.h>
+
+FILE *__cdecl tmpfile(void)
+{
+    /* GetTempPathA() requires buffer of size MAX_PATH+1
+     * and tmpnam() requires buffer of size L_tmpnam.
+     */
+    char path[MAX_PATH+1+L_tmpnam];
+    DWORD len;
+    int fd;
+    FILE *file;
+
+    len = GetTempPathA(MAX_PATH, path);
+    if (len == 0 || len > MAX_PATH) {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    /* Function tmpnam() generates path name starting with backslash,
+     * so ensure that the temp directory path does not contain it.
+     */
+    if (path[len-1] == '\\')
+        len--;
+
+    /* Generate temporary file path and exclusively create+open it in binary 
mode.
+     * If the generated temporary file path already exist then generate new 
one again.
+     * Note that we cannot use fopen() because msvcrt does not support 
exclusive 'x' mode.
+     * Use open() with O_CREAT | O_EXCL flags followed by the fdopen() to get 
FILE* stream.
+     */
+    do {
+        if (tmpnam(path+len) != path+len)
+            return NULL;
+        fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_TEMPORARY, 
S_IREAD | S_IWRITE);
+        if (fd < 0 && errno != EEXIST)
+            return NULL;
+    } while (fd < 0);
+
+    file = fdopen(fd, "r+b");
+    if (!file) {
+        int saved_errno = errno;
+        close(fd);
+        errno = saved_errno;
+        return NULL;
+    }
+
+    /* Mark the associated FILE* stream as temporary, so the _rmtmp() can 
remove it. */
+    file->_tmpfname = strdup(path);
+    if (!file->_tmpfname) {
+        fclose(file);
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    return file;
+}
+FILE * (__cdecl *__MINGW_IMP_SYMBOL(tmpfile))(void) = tmpfile;
+
+FILE * __attribute__((alias("tmpfile"))) __cdecl tmpfile64(void);
+extern FILE * (__cdecl 
*__attribute__((alias(__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(tmpfile))))) 
__MINGW_IMP_SYMBOL(tmpfile64))(void);
diff --git a/mingw-w64-crt/testcases/Makefile.am 
b/mingw-w64-crt/testcases/Makefile.am
index 889439141918..60c22062491e 100644
--- a/mingw-w64-crt/testcases/Makefile.am
+++ b/mingw-w64-crt/testcases/Makefile.am
@@ -60,6 +60,7 @@ testcase_progs = \
   t_stdint \
   t_time \
   t_tls1 \
+  t_tmpfile \
   t_trycatch \
   t_stat_slash \
   t_vsscanf \
diff --git a/mingw-w64-crt/testcases/t_lfs.c b/mingw-w64-crt/testcases/t_lfs.c
index a5a33ce97126..cf8f313cc5b5 100644
--- a/mingw-w64-crt/testcases/t_lfs.c
+++ b/mingw-w64-crt/testcases/t_lfs.c
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <assert.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
@@ -23,7 +24,8 @@ int main(int argc, char *argv[]) {
         fclose(file);
     }
     file = tmpfile64();
-    if (file) fclose(file);
+    assert(file != NULL);
+    fclose(file);
     fd = open64(argc >= 2 ? argv[1] : argv[0], O_RDONLY);
     if (fd >= 0) close(fd);
     return 0;
diff --git a/mingw-w64-crt/testcases/t_tmpfile.c 
b/mingw-w64-crt/testcases/t_tmpfile.c
new file mode 100644
index 000000000000..c75e99c1f8e5
--- /dev/null
+++ b/mingw-w64-crt/testcases/t_tmpfile.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <direct.h>
+#include <assert.h>
+
+int main() {
+    FILE *file;
+
+    /* ensure that tmpfile() works also when cwd is in C:\Windows */
+    assert(chdir("C:\\Windows\\") == 0);
+
+    file = tmpfile();
+    assert(file);
+
+    assert(fputs("test", file) >= 0);
+    assert(fflush(file) == 0);
+
+    /* ensure that _rmtmp() works also for emulated mingw-w64 tmpfile() 
implementation */
+    assert(_rmtmp() == 1);
+
+    return 0;
+}
-- 
2.20.1



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to