bug-gnulib
[Top][All Lists]
Advanced

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

Re: fix inadequate Windows implementation of tmpfile


From: Bruno Haible
Subject: Re: fix inadequate Windows implementation of tmpfile
Date: Sat, 17 Feb 2007 16:13:08 +0100
User-agent: KMail/1.5.4

Paul Eggert wrote:
> I think gnulib is for porting GNU applications, and if GNU
> applications assume glibc behavior for a function then it's OK to
> replace a vendor's function that behaves differrently.

OK. So I'm adding Ben's module, with the following modifications:
  * tmpfile.c:
    - Don't use _O_TEMPORARY on Windows 95/98/ME.
    - Provide an 'errno' in the case of the first 'goto done'.
    - Restructure the code so as to avoid 'goto'.
    - Allocate 'dir' and 'xtemplate' on the stack, since their size is
      bounded by PATH_MAX (<= 4096 or so).
    - Change range check to allow paths of length PATH_MAX - 1.
  * tmpfile.m4:
    - Change the configure message. (If the message says "for tmpfile that only
      uses the root directory", it should also test for this behaviour.)
    - Use AC_EGREP_CPP instead of AC_COMPILE_IFELSE, since it's faster.
    - Actually invoke gl_PREREQ_TMPFILE.
  * modules/tmpfile:
    - Don't mention "Windows" in the module description. The module description
      should be abstract enough that it doesn't need to change if problems
      appear on other platforms.
    - Mention <stdio.h> as header file to be included.
  * MODULES.html.sh: Put new section about <stdio.h> before <stdlib.h>, not
    between <stdlib.h> and <stdlib.h>.

Please proofread again. Did I miss something?

2007-02-17  Ben Pfaff  <address@hidden>
            Bruno Haible  <address@hidden>

        * modules/tmpfile: New file.
        * lib/tmpfile.c: New file.
        * m4/tmpfile.m4: New file.
        * MODULES.html.sh (func_all_modules): New section "Input/output".

================================ modules/tmpfile =============================
Description:
tmpfile() function: create a temporary file.

Files:
lib/tmpfile.c
m4/tmpfile.m4

Depends-on:
pathmax
tempname
tmpdir

configure.ac:
gl_TMPFILE

Makefile.am:

Include:
#include <stdio.h>

License:
GPL

Maintainer:
Ben Pfaff
================================= lib/tmpfile.c ==============================
/* Create a temporary file.
   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>

/* Specification.  */
#include <stdio.h>

/* This replacement is used only on native Windows platforms.  */

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>

#include <io.h>

#define WIN32_LEAN_AND_MEAN  /* avoid including junk */
#include <windows.h>

#include "pathmax.h"
#include "tempname.h"
#include "tmpdir.h"

/* 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);
}

FILE *
tmpfile (void)
{
  char dir[PATH_MAX];
  DWORD retval;

  /* 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 directory (unless $TMPDIR is set). */
  retval = GetTempPath (PATH_MAX, dir);
  if (retval > 0 && retval < PATH_MAX)
    {
      char xtemplate[PATH_MAX];

      if (path_search (xtemplate, PATH_MAX, dir, NULL, true) >= 0)
        {
          size_t len = strlen (xtemplate);
          int o_temporary = (supports_delete_on_close () ? _O_TEMPORARY : 0);
          int fd;

          do
            {
              memcpy (&xtemplate[len - 6], "XXXXXX", 6);
              if (gen_tempname (xtemplate, GT_NOCREATE) < 0)
                {
                  fd = -1;
                  break;
                }

              fd = _open (xtemplate,
                          _O_CREAT | _O_EXCL | o_temporary
                          | _O_RDWR | _O_BINARY,
                          _S_IREAD | _S_IWRITE);
            }
          while (fd < 0 && errno == EEXIST);

          if (fd >= 0)
            {
              FILE *fp = _fdopen (fd, "w+b");

              if (fp != NULL)
                return fp;
              else
                {
                  int saved_errno = errno;
                  _close (fd);
                  errno = saved_errno;
                }
            }
        }
    }
  else
    {
      if (retval > 0)
        errno = ENAMETOOLONG;
      else
        /* Ideally this should translate GetLastError () to an errno value.  */
        errno = ENOENT;
    }

  return NULL;
}
================================= m4/tmpfile.m4 ==============================
# Check whether to use a replacement tmpfile() function.

# 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.

# The native Windows tmpfile function always tries to put the temporary
# file in the root directory.  (This behaviour is even documented in
# Microsoft's documentation!)  This often fails for ordinary users who
# don't have the permissions to write in the root directory.
#
# 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 platform (excluding Cygwin).

AC_DEFUN([gl_TMPFILE], [
  AC_CACHE_CHECK([whether tmpfile should be overridden],
    [gl_cv_func_tmpfile_unusable],
    [AC_EGREP_CPP([choke me], [
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
choke me
#endif
       ],
       [gl_cv_func_tmpfile_unusable=yes],
       [gl_cv_func_tmpfile_unusable=no])])
  if test $gl_cv_func_tmpfile_unusable = yes; then
    AC_LIBOBJ(tmpfile)
    AC_DEFINE(tmpfile, rpl_tmpfile,
      [Define to rpl_tmpfile if the replacement function should be used.])
    gl_PREREQ_TMPFILE
  fi
])

# Prerequisites of lib/tmpfile.c.
AC_DEFUN([gl_PREREQ_TMPFILE], [:])
==============================================================================
*** MODULES.html.sh     15 Feb 2007 03:07:04 -0000      1.194
--- MODULES.html.sh     17 Feb 2007 15:03:27 -0000
***************
*** 1524,1529 ****
--- 1524,1539 ----
    func_module verify
    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="Memory management functions <stdlib.h>"
    element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"`
    func_section_wrap ansic_enh_stdlib_memory





reply via email to

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