+
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+/* On Windows, opening a file with _O_TEMPORARY has the effect of passing
+ the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect
+ of deleting the file when it is closed - even when the program crashes.
+ But (according to the Cygwin sources) it works only on Windows NT or newer.
+ So we cache the info whether we are running on Windows NT or newer. */
+
+static bool
+supports_delete_on_close ()
+{
+ static int known; /* 1 = yes, -1 = no, 0 = unknown */
+ if (!known)
+ {
+ OSVERSIONINFO v;
+
+ if (GetVersionEx (&v))
+ known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
+ else
+ known = -1;
+ }
+ return (known > 0);
+}
+
+#endif
+
+
+/* Register a file descriptor to be closed. */
+static void
+register_fd (int fd)
+{
+ if (descriptors == NULL)
+ descriptors = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, NULL,
+ false);
+ gl_list_add_first (descriptors, (void *) (uintptr_t) fd);
+}
+
+/* Unregister a file descriptor to be closed. */
+static void
+unregister_fd (int fd)
+{
+ gl_list_t fds = descriptors;
+ gl_list_node_t node;
+
+ if (fds == NULL)
+ /* descriptors should already contain fd. */
+ abort ();
+ node = gl_list_search (fds, (void *) (uintptr_t) fd);
+ if (node == NULL)
+ /* descriptors should already contain fd. */
+ abort ();
+ gl_list_remove_node (fds, node);
+}
+
+/* Open a temporary file in a temporary directory.
+ Registers the resulting file descriptor to be closed. */
+int
+open_temp (const char *file_name, int flags, mode_t mode)
+{
+ int fd;
+ int saved_errno;
+
+ block_fatal_signals ();
+ /* Note: 'open' here is actually open() or open_safer(). */
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* Use _O_TEMPORARY when possible, to increase the chances that the
+ temporary file is removed when the process crashes. */
+ if (supports_delete_on_close ())
+ fd = open (file_name, flags | _O_TEMPORARY, mode);
+ else
+#endif
+ fd = open (file_name, flags, mode);
+ saved_errno = errno;
+ if (fd >= 0)
+ register_fd (fd);
+ unblock_fatal_signals ();
+ errno = saved_errno;
+ return fd;
+}
+
+/* Open a temporary file in a temporary directory.
+ Registers the resulting file descriptor to be closed. */
+FILE *
+fopen_temp (const char *file_name, const char *mode)
+{
+ FILE *fp;
+ int saved_errno;
+
+ block_fatal_signals ();
+ /* Note: 'fopen' here is actually fopen() or fopen_safer(). */
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* Use _O_TEMPORARY when possible, to increase the chances that the
+ temporary file is removed when the process crashes. */
+ if (supports_delete_on_close ())
+ {
+ size_t mode_len = strlen (mode);
+ char *augmented_mode = (char *) xmalloca (mode_len + 2);
+ memcpy (augmented_mode, mode, mode_len);
+ memcpy (augmented_mode + mode_len, "D", 2);
+
+ fp = fopen (file_name, augmented_mode);
+ saved_errno = errno;
+
+ freea (augmented_mode);
+ }
+ else
+#endif
+ {
+ fp = fopen (file_name, mode);
+ saved_errno = errno;
+ }
+ if (fp != NULL)
+ {
+ /* It is sufficient to register fileno (fp) instead of the entire fp,
+ because at cleanup time there is no need to do an fflush (fp); a
+ close (fileno (fp)) will be enough. */
+ int fd = fileno (fp);
+ if (!(fd >= 0))
+ abort ();
+ register_fd (fd);
+ }
+ unblock_fatal_signals ();
+ errno = saved_errno;
+ return fp;
+}
+
+/* Close a temporary file in a temporary directory.
+ Unregisters the previously registered file descriptor. */
+int
+close_temp (int fd)
+{
+ if (fd >= 0)
+ {
+ /* No blocking of signals is needed here, since a double close of a
+ file descriptor is harmless. */
+ int result = close (fd);
+ int saved_errno = errno;
+
+ /* No race condition here: we assume a single-threaded program, hence
+ fd cannot be re-opened here. */
+
+ unregister_fd (fd);
+
+ errno = saved_errno;
+ return result;
+ }
+ else
+ return close (fd);
+}
+
+/* Close a temporary file in a temporary directory.
+ Unregisters the previously registered file descriptor. */
+int
+fclose_temp (FILE *fp)
+{
+ int fd = fileno (fp);
+ /* No blocking of signals is needed here, since a double close of a
+ file descriptor is harmless. */
+ int result = fclose (fp);
+ int saved_errno = errno;
+
+ /* No race condition here: we assume a single-threaded program, hence
+ fd cannot be re-opened here. */
+
+ unregister_fd (fd);
+
+ errno = saved_errno;
+ return result;
+}
+
+#if GNULIB_FWRITEERROR
+/* Like fwriteerror.
+ Unregisters the previously registered file descriptor. */
+int
+fwriteerror_temp (FILE *fp)
+{
+ int fd = fileno (fp);
+ /* No blocking of signals is needed here, since a double close of a
+ file descriptor is harmless. */
+ int result = fwriteerror (fp);
+ int saved_errno = errno;
+
+ /* No race condition here: we assume a single-threaded program, hence
+ fd cannot be re-opened here. */
+
+ unregister_fd (fd);
+
+ errno = saved_errno;
+ return result;
+}
+#endif
+
+#if GNULIB_CLOSE_STREAM
+/* Like close_stream.
+ Unregisters the previously registered file descriptor. */
+int
+close_stream_temp (FILE *fp)
+{
+ int fd = fileno (fp);
+ /* No blocking of signals is needed here, since a double close of a
+ file descriptor is harmless. */
+ int result = close_stream (fp);
+ int saved_errno = errno;
+
+ /* No race condition here: we assume a single-threaded program, hence
+ fd cannot be re-opened here. */
+
+ unregister_fd (fd);
+
+ errno = saved_errno;
+ return result;
+}
+#endif