root/maint/gnulib/lib/tmpfile.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. supports_delete_on_close
  2. tmpfile
  3. tmpfile

   1 /* Create a temporary file.
   2    Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 3 of the
   7    License, or (at your option) any later version.
   8 
   9    This file is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Ben Pfaff. */
  18 
  19 #include <config.h>
  20 
  21 /* Specification.  */
  22 #include <stdio.h>
  23 
  24 #include <errno.h>
  25 #include <stdbool.h>
  26 
  27 #if defined _WIN32 && ! defined __CYGWIN__
  28 /* A native Windows platform.  */
  29 
  30 # include <fcntl.h>
  31 # include <string.h>
  32 # include <sys/stat.h>
  33 
  34 # include <io.h>
  35 
  36 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
  37 # include <windows.h>
  38 
  39 #else
  40 
  41 # include <unistd.h>
  42 
  43 #endif
  44 
  45 #include "pathmax.h"
  46 #include "tempname.h"
  47 #include "tmpdir.h"
  48 
  49 /* PATH_MAX is guaranteed to be defined, because this replacement is only
  50    used on native Windows and Android.  */
  51 
  52 #if defined _WIN32 && ! defined __CYGWIN__
  53 /* A native Windows platform.  */
  54 
  55 /* Don't assume that UNICODE is not defined.  */
  56 # undef OSVERSIONINFO
  57 # define OSVERSIONINFO OSVERSIONINFOA
  58 # undef GetVersionEx
  59 # define GetVersionEx GetVersionExA
  60 # undef GetTempPath
  61 # define GetTempPath GetTempPathA
  62 
  63 /* On Windows, opening a file with _O_TEMPORARY has the effect of passing
  64    the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect
  65    of deleting the file when it is closed - even when the program crashes.
  66    But (according to the Cygwin sources) it works only on Windows NT or newer.
  67    So we cache the info whether we are running on Windows NT or newer.  */
  68 
  69 static bool
  70 supports_delete_on_close ()
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72   static int known; /* 1 = yes, -1 = no, 0 = unknown */
  73   if (!known)
  74     {
  75       OSVERSIONINFO v;
  76 
  77       /* According to
  78          <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getversionexa>
  79          this structure must be initialized as follows:  */
  80       v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  81 
  82       if (GetVersionEx (&v))
  83         known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
  84       else
  85         known = -1;
  86     }
  87   return (known > 0);
  88 }
  89 
  90 FILE *
  91 tmpfile (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93   char dir[PATH_MAX];
  94   DWORD retval;
  95 
  96   /* Find Windows temporary file directory.
  97      We provide this as the directory argument to path_search because Windows
  98      defines P_tmpdir to "\\" and will therefore try to put all temporary files
  99      in the root directory (unless $TMPDIR is set). */
 100   retval = GetTempPath (PATH_MAX, dir);
 101   if (retval > 0 && retval < PATH_MAX)
 102     {
 103       char xtemplate[PATH_MAX];
 104 
 105       if (path_search (xtemplate, PATH_MAX, dir, NULL, true) >= 0)
 106         {
 107           size_t len = strlen (xtemplate);
 108           int o_temporary = (supports_delete_on_close () ? _O_TEMPORARY : 0);
 109           int fd;
 110 
 111           do
 112             {
 113               memcpy (&xtemplate[len - 6], "XXXXXX", 6);
 114               if (gen_tempname (xtemplate, 0, 0, GT_NOCREATE) < 0)
 115                 {
 116                   fd = -1;
 117                   break;
 118                 }
 119 
 120               fd = _open (xtemplate,
 121                           _O_CREAT | _O_EXCL | o_temporary
 122                           | _O_RDWR | _O_BINARY,
 123                           _S_IREAD | _S_IWRITE);
 124             }
 125           while (fd < 0 && errno == EEXIST);
 126 
 127           if (fd >= 0)
 128             {
 129               FILE *fp = _fdopen (fd, "w+b");
 130 
 131               if (fp != NULL)
 132                 return fp;
 133               else
 134                 {
 135                   int saved_errno = errno;
 136                   _close (fd);
 137                   errno = saved_errno;
 138                 }
 139             }
 140         }
 141     }
 142   else
 143     {
 144       if (retval > 0)
 145         errno = ENAMETOOLONG;
 146       else
 147         /* Ideally this should translate GetLastError () to an errno value.  */
 148         errno = ENOENT;
 149     }
 150 
 151   return NULL;
 152 }
 153 
 154 #else
 155 
 156 FILE *
 157 tmpfile (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159   char buf[PATH_MAX];
 160   int fd;
 161   FILE *fp;
 162 
 163   /* Try $TMPDIR first, not /tmp nor P_tmpdir, because we need this replacement
 164      on Android, and /tmp does not exist on Android.  */
 165 
 166   if (path_search (buf, sizeof buf, NULL, "tmpf", true))
 167     return NULL;
 168 
 169   fd = gen_tempname (buf, 0, 0, GT_FILE);
 170   if (fd < 0)
 171     return NULL;
 172 
 173   /* Note that this relies on the Unix semantics that
 174      a file is not really removed until it is closed.  */
 175   (void) unlink (buf);
 176 
 177   if ((fp = fdopen (fd, "w+b")) == NULL)
 178     {
 179       int saved_errno = errno;
 180       close (fd);
 181       errno = saved_errno;
 182     }
 183 
 184   return fp;
 185 }
 186 
 187 #endif

/* [previous][next][first][last][top][bottom][index][help] */