bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

fix inadequate Windows implementation of tmpfile


From: Ben Pfaff
Subject: fix inadequate Windows implementation of tmpfile
Date: Thu, 15 Feb 2007 07:25:03 -0800
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux)

Under Windows, the tmpfile function is defined to always create
its temporary file in the root directory.  Most users don't have
permission to do that, so it will often fail.  I'm proposing a
"tmpfile" module that detects this situation and replaces tmpfile
with a better implementation.

The implementation I provide is Windows-specific, because the
common Unix implementation of temporary files (open then
immediately unlink) doesn't work on Windows, which doesn't permit
deleting open files.  I using the clean-temp module instead, as a
more portable solution, but then I needed to interpose upon
fclose (and perhaps close as well) to delete the temporary file
when it was closed, which quickly turned into a mess.  Using the
Windows "delete on close" _O_TEMPORARY flag is a simpler
solution.

I've tested this solution on mingw/Wine and it works well there.
I haven't tested it on a real Windows machine because I don't
have easy access to one.

All feedback is appreciated.

Index: MODULES.html.sh
===================================================================
RCS file: /cvsroot/gnulib/gnulib/MODULES.html.sh,v
retrieving revision 1.194
diff -u -p -r1.194 MODULES.html.sh
--- MODULES.html.sh     15 Feb 2007 03:07:04 -0000      1.194
+++ MODULES.html.sh     15 Feb 2007 15:18:20 -0000
@@ -1539,6 +1539,16 @@ func_all_modules ()
   func_module pagealign_alloc
   func_end_table
 
+  element="Input/Output <stdio.h>"
+  element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"`
+  func_section_wrap ansic_enh_stdio
+  func_wrap H3
+  func_echo "$element"
+
+  func_begin_table
+  func_module tmpfile
+  func_end_table
+
   element="Sorting functions <stdlib.h>"
   element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"`
   func_section_wrap ansic_enh_stdlib_sorting
Index: lib/tmpfile.c
===================================================================
RCS file: lib/tmpfile.c
diff -N lib/tmpfile.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/tmpfile.c       15 Feb 2007 15:18:21 -0000
@@ -0,0 +1,89 @@
+/* Replacement for inadequate Windows implementation of tmpfile.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Ben Pfaff. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "pathmax.h"
+#include "xallocsa.h"
+#include "tempname.h"
+#include "tmpdir.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+FILE *
+tmpfile (void)
+{
+  char *dir;
+  char *xtemplate;
+  DWORD retval;
+  size_t len;
+  int fd;
+  FILE *file = NULL;
+
+  dir = (char *) xallocsa (PATH_MAX);
+  xtemplate = (char *) xallocsa (PATH_MAX);
+
+  /* Find Windows temporary file directory.
+     We provide this as the directory argument to path_search
+     because Windows defines P_tmpdir to "\\" and will therefore
+     try to put all temporary files in the root (unless $TMPDIR
+     is set). */
+  retval = GetTempPath (PATH_MAX, dir);
+  if (retval == 0 || retval >= PATH_MAX - 1)
+    goto done;
+  
+  if (path_search (xtemplate, PATH_MAX, dir, NULL, true))
+    goto done;
+  len = strlen (xtemplate);
+
+  do
+    {
+      strcpy (&xtemplate[len - 6], "XXXXXX");
+      if (gen_tempname (xtemplate, GT_NOCREATE))
+        goto done;
+      
+      fd = _open (xtemplate,
+                  _O_BINARY | _O_CREAT | _O_TEMPORARY | _O_EXCL | _O_RDWR,
+                  _S_IREAD | _S_IWRITE); 
+    }
+  while (fd < 0 && errno == EEXIST);
+  if (fd < 0)
+    goto done;
+      
+  file = _fdopen (fd, "w+b");
+  if (file == NULL) 
+    {
+      int save_errno = errno;
+      _close (fd);
+      errno = save_errno;
+    }
+
+ done:
+  freesa (xtemplate);
+  freesa (dir);
+  return file;
+}
Index: m4/tmpfile.m4
===================================================================
RCS file: m4/tmpfile.m4
diff -N m4/tmpfile.m4
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ m4/tmpfile.m4       15 Feb 2007 15:18:21 -0000
@@ -0,0 +1,39 @@
+# Check whether tmpfile will work for ordinary users who do not have
+# permissions to write in the root directory.
+
+# Copyright (C) 2007 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Ben Pfaff.
+
+# Check for inadequate Windows tmpfile, which only tries to put the
+# temporary file in the root directory and thus often fails.
+
+# We can't test for tmpfile even at runtime, since our test program
+# might be running with privileges that allow it to write to the root
+# directory, even though tmpfile wouldn't work in general.
+
+# Instead, just test for a Windows host.  Microsoft defines tmpfile on
+# Windows to always create a file in the root directory, so this
+# should be a reliable test.
+
+AC_DEFUN([gl_TMPFILE], [
+  AC_CACHE_CHECK([for tmpfile that only uses the root directory],
+                [gl_cv_func_tmpfile_root_only],
+                [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>],
+                                                    [[#ifdef __WIN32__
+                                                      choke me
+                                                      #endif ]])],
+                                   [gl_cv_func_tmpfile_root_only=no],
+                                   [gl_cv_func_tmpfile_root_only=yes])])
+  if test $gl_cv_func_tmpfile_root_only = yes; then
+    AC_LIBOBJ(tmpfile)
+    AC_DEFINE(tmpfile, rpl_tmpfile,
+      [Define to rpl_tmpfile if the replacement function should be used.])
+  fi
+])
+
+# Prerequisites of lib/free.c.
+AC_DEFUN([gl_PREREQ_TMPFILE], [:])
Index: modules/tmpfile
===================================================================
RCS file: modules/tmpfile
diff -N modules/tmpfile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ modules/tmpfile     15 Feb 2007 15:18:22 -0000
@@ -0,0 +1,25 @@
+Description:
+higher quality tmpfile function for Windows targets
+
+Files:
+lib/tmpfile.c
+m4/tmpfile.m4
+
+Depends-on:
+pathmax
+tempname
+tmpdir
+xallocsa
+
+configure.ac:
+gl_TMPFILE
+
+Makefile.am:
+
+Include:
+
+License:
+GPL
+
+Maintainer:
+Ben Pfaff


-- 
"In this world that Hugh Heffner had made,
 he alone seemed forever bunnyless."
--John D. MacDonald





reply via email to

[Prev in Thread] Current Thread [Next in Thread]