Imported Upstream version 1.4.17
[platform/upstream/m4.git] / lib / clean-temp.c
1 /* Temporary directories and temporary files with automatic cleanup.
2    Copyright (C) 2001, 2003, 2006-2007, 2009-2013 Free Software Foundation,
3    Inc.
4    Written by Bruno Haible <bruno@clisp.org>, 2006.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19
20 #include <config.h>
21
22 /* Specification.  */
23 #include "clean-temp.h"
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
34 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
35 # include <windows.h>
36 #endif
37
38 #include "error.h"
39 #include "fatal-signal.h"
40 #include "pathmax.h"
41 #include "tmpdir.h"
42 #include "xalloc.h"
43 #include "xmalloca.h"
44 #include "gl_xlist.h"
45 #include "gl_linkedhash_list.h"
46 #include "gettext.h"
47 #if GNULIB_FWRITEERROR
48 # include "fwriteerror.h"
49 #endif
50 #if GNULIB_CLOSE_STREAM
51 # include "close-stream.h"
52 #endif
53 #if GNULIB_FCNTL_SAFER
54 # include "fcntl--.h"
55 #endif
56 #if GNULIB_FOPEN_SAFER
57 # include "stdio--.h"
58 #endif
59
60 #define _(str) gettext (str)
61
62 /* GNU Hurd doesn't have PATH_MAX.  Use a fallback.
63    Temporary directory names are usually not that long.  */
64 #ifndef PATH_MAX
65 # define PATH_MAX 1024
66 #endif
67
68 #ifndef uintptr_t
69 # define uintptr_t unsigned long
70 #endif
71
72 #if !GNULIB_FCNTL_SAFER
73 /* The results of open() in this file are not used with fchdir,
74    therefore save some unnecessary work in fchdir.c.  */
75 # undef open
76 # undef close
77 #endif
78
79
80 /* The use of 'volatile' in the types below (and ISO C 99 section 5.1.2.3.(5))
81    ensure that while constructing or modifying the data structures, the field
82    values are written to memory in the order of the C statements.  So the
83    signal handler can rely on these field values to be up to date.  */
84
85
86 /* Registry for a single temporary directory.
87    'struct temp_dir' from the public header file overlaps with this.  */
88 struct tempdir
89 {
90   /* The absolute pathname of the directory.  */
91   char * volatile dirname;
92   /* Whether errors during explicit cleanup are reported to standard error.  */
93   bool cleanup_verbose;
94   /* Absolute pathnames of subdirectories.  */
95   gl_list_t /* <char *> */ volatile subdirs;
96   /* Absolute pathnames of files.  */
97   gl_list_t /* <char *> */ volatile files;
98 };
99
100 /* List of all temporary directories.  */
101 static struct
102 {
103   struct tempdir * volatile * volatile tempdir_list;
104   size_t volatile tempdir_count;
105   size_t tempdir_allocated;
106 } cleanup_list /* = { NULL, 0, 0 } */;
107
108 /* List of all open file descriptors to temporary files.  */
109 static gl_list_t /* <int> */ volatile descriptors;
110
111
112 /* For the subdirs and for the files, we use a gl_list_t of type LINKEDHASH.
113    Why?  We need a data structure that
114
115      1) Can contain an arbitrary number of 'char *' values.  The strings
116         are compared via strcmp, not pointer comparison.
117      2) Has insertion and deletion operations that are fast: ideally O(1),
118         or possibly O(log n).  This is important for GNU sort, which may
119         create a large number of temporary files.
120      3) Allows iteration through all elements from within a signal handler.
121      4) May or may not allow duplicates.  It doesn't matter here, since
122         any file or subdir can only be removed once.
123
124    Criterion 1) would allow any gl_list_t or gl_oset_t implementation.
125
126    Criterion 2) leaves only GL_LINKEDHASH_LIST, GL_TREEHASH_LIST, or
127    GL_TREE_OSET.
128
129    Criterion 3) puts at disadvantage GL_TREEHASH_LIST and GL_TREE_OSET.
130    Namely, iteration through the elements of a binary tree requires access
131    to many ->left, ->right, ->parent pointers. However, the rebalancing
132    code for insertion and deletion in an AVL or red-black tree is so
133    complicated that we cannot assume that >left, ->right, ->parent pointers
134    are in a consistent state throughout these operations.  Therefore, to
135    avoid a crash in the signal handler, all destructive operations to the
136    lists would have to be protected by a
137        block_fatal_signals ();
138        ...
139        unblock_fatal_signals ();
140    pair.  Which causes extra system calls.
141
142    Criterion 3) would also discourage GL_ARRAY_LIST and GL_CARRAY_LIST,
143    if they were not already excluded.  Namely, these implementations use
144    xrealloc(), leaving a time window in which in the list->elements pointer
145    points to already deallocated memory.  To avoid a crash in the signal
146    handler at such a moment, all destructive operations would have to
147    protected by block/unblock_fatal_signals (), in this case too.
148
149    A list of type GL_LINKEDHASH_LIST without duplicates fulfills all
150    requirements:
151      2) Insertion and deletion are O(1) on average.
152      3) The gl_list_iterator, gl_list_iterator_next implementations do
153         not trigger memory allocations, nor other system calls, and are
154         therefore safe to be called from a signal handler.
155         Furthermore, since SIGNAL_SAFE_LIST is defined, the implementation
156         of the destructive functions ensures that the list structure is
157         safe to be traversed at any moment, even when interrupted by an
158         asynchronous signal.
159  */
160
161 /* String equality and hash code functions used by the lists.  */
162
163 static bool
164 string_equals (const void *x1, const void *x2)
165 {
166   const char *s1 = (const char *) x1;
167   const char *s2 = (const char *) x2;
168   return strcmp (s1, s2) == 0;
169 }
170
171 #define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
172
173 /* A hash function for NUL-terminated char* strings using
174    the method described by Bruno Haible.
175    See http://www.haible.de/bruno/hashfunc.html.  */
176 static size_t
177 string_hash (const void *x)
178 {
179   const char *s = (const char *) x;
180   size_t h = 0;
181
182   for (; *s; s++)
183     h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
184
185   return h;
186 }
187
188
189 /* The signal handler.  It gets called asynchronously.  */
190 static void
191 cleanup ()
192 {
193   size_t i;
194
195   /* First close all file descriptors to temporary files.  */
196   {
197     gl_list_t fds = descriptors;
198
199     if (fds != NULL)
200       {
201         gl_list_iterator_t iter;
202         const void *element;
203
204         iter = gl_list_iterator (fds);
205         while (gl_list_iterator_next (&iter, &element, NULL))
206           {
207             int fd = (int) (uintptr_t) element;
208             close (fd);
209           }
210         gl_list_iterator_free (&iter);
211       }
212   }
213
214   for (i = 0; i < cleanup_list.tempdir_count; i++)
215     {
216       struct tempdir *dir = cleanup_list.tempdir_list[i];
217
218       if (dir != NULL)
219         {
220           gl_list_iterator_t iter;
221           const void *element;
222
223           /* First cleanup the files in the subdirectories.  */
224           iter = gl_list_iterator (dir->files);
225           while (gl_list_iterator_next (&iter, &element, NULL))
226             {
227               const char *file = (const char *) element;
228               unlink (file);
229             }
230           gl_list_iterator_free (&iter);
231
232           /* Then cleanup the subdirectories.  */
233           iter = gl_list_iterator (dir->subdirs);
234           while (gl_list_iterator_next (&iter, &element, NULL))
235             {
236               const char *subdir = (const char *) element;
237               rmdir (subdir);
238             }
239           gl_list_iterator_free (&iter);
240
241           /* Then cleanup the temporary directory itself.  */
242           rmdir (dir->dirname);
243         }
244     }
245 }
246
247 /* Create a temporary directory.
248    PREFIX is used as a prefix for the name of the temporary directory. It
249    should be short and still give an indication about the program.
250    PARENTDIR can be used to specify the parent directory; if NULL, a default
251    parent directory is used (either $TMPDIR or /tmp or similar).
252    CLEANUP_VERBOSE determines whether errors during explicit cleanup are
253    reported to standard error.
254    Return a fresh 'struct temp_dir' on success.  Upon error, an error message
255    is shown and NULL is returned.  */
256 struct temp_dir *
257 create_temp_dir (const char *prefix, const char *parentdir,
258                  bool cleanup_verbose)
259 {
260   struct tempdir * volatile *tmpdirp = NULL;
261   struct tempdir *tmpdir;
262   size_t i;
263   char *xtemplate;
264   char *tmpdirname;
265
266   /* See whether it can take the slot of an earlier temporary directory
267      already cleaned up.  */
268   for (i = 0; i < cleanup_list.tempdir_count; i++)
269     if (cleanup_list.tempdir_list[i] == NULL)
270       {
271         tmpdirp = &cleanup_list.tempdir_list[i];
272         break;
273       }
274   if (tmpdirp == NULL)
275     {
276       /* See whether the array needs to be extended.  */
277       if (cleanup_list.tempdir_count == cleanup_list.tempdir_allocated)
278         {
279           /* Note that we cannot use xrealloc(), because then the cleanup()
280              function could access an already deallocated array.  */
281           struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
282           size_t old_allocated = cleanup_list.tempdir_allocated;
283           size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
284           struct tempdir * volatile *new_array =
285             XNMALLOC (new_allocated, struct tempdir * volatile);
286
287           if (old_allocated == 0)
288             /* First use of this facility.  Register the cleanup handler.  */
289             at_fatal_signal (&cleanup);
290           else
291             {
292               /* Don't use memcpy() here, because memcpy takes non-volatile
293                  arguments and is therefore not guaranteed to complete all
294                  memory stores before the next statement.  */
295               size_t k;
296
297               for (k = 0; k < old_allocated; k++)
298                 new_array[k] = old_array[k];
299             }
300
301           cleanup_list.tempdir_list = new_array;
302           cleanup_list.tempdir_allocated = new_allocated;
303
304           /* Now we can free the old array.  */
305           if (old_array != NULL)
306             free ((struct tempdir **) old_array);
307         }
308
309       tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
310       /* Initialize *tmpdirp before incrementing tempdir_count, so that
311          cleanup() will skip this entry before it is fully initialized.  */
312       *tmpdirp = NULL;
313       cleanup_list.tempdir_count++;
314     }
315
316   /* Initialize a 'struct tempdir'.  */
317   tmpdir = XMALLOC (struct tempdir);
318   tmpdir->dirname = NULL;
319   tmpdir->cleanup_verbose = cleanup_verbose;
320   tmpdir->subdirs = gl_list_create_empty (GL_LINKEDHASH_LIST,
321                                           string_equals, string_hash, NULL,
322                                           false);
323   tmpdir->files = gl_list_create_empty (GL_LINKEDHASH_LIST,
324                                         string_equals, string_hash, NULL,
325                                         false);
326
327   /* Create the temporary directory.  */
328   xtemplate = (char *) xmalloca (PATH_MAX);
329   if (path_search (xtemplate, PATH_MAX, parentdir, prefix, parentdir == NULL))
330     {
331       error (0, errno,
332              _("cannot find a temporary directory, try setting $TMPDIR"));
333       goto quit;
334     }
335   block_fatal_signals ();
336   tmpdirname = mkdtemp (xtemplate);
337   if (tmpdirname != NULL)
338     {
339       tmpdir->dirname = tmpdirname;
340       *tmpdirp = tmpdir;
341     }
342   unblock_fatal_signals ();
343   if (tmpdirname == NULL)
344     {
345       error (0, errno,
346              _("cannot create a temporary directory using template \"%s\""),
347              xtemplate);
348       goto quit;
349     }
350   /* Replace tmpdir->dirname with a copy that has indefinite extent.
351      We cannot do this inside the block_fatal_signals/unblock_fatal_signals
352      block because then the cleanup handler would not remove the directory
353      if xstrdup fails.  */
354   tmpdir->dirname = xstrdup (tmpdirname);
355   freea (xtemplate);
356   return (struct temp_dir *) tmpdir;
357
358  quit:
359   freea (xtemplate);
360   return NULL;
361 }
362
363 /* Register the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
364    needs to be removed before DIR can be removed.
365    Should be called before the file ABSOLUTE_FILE_NAME is created.  */
366 void
367 register_temp_file (struct temp_dir *dir,
368                     const char *absolute_file_name)
369 {
370   struct tempdir *tmpdir = (struct tempdir *)dir;
371
372   /* Add absolute_file_name to tmpdir->files, without duplicates.  */
373   if (gl_list_search (tmpdir->files, absolute_file_name) == NULL)
374     gl_list_add_first (tmpdir->files, xstrdup (absolute_file_name));
375 }
376
377 /* Unregister the given ABSOLUTE_FILE_NAME as being a file inside DIR, that
378    needs to be removed before DIR can be removed.
379    Should be called when the file ABSOLUTE_FILE_NAME could not be created.  */
380 void
381 unregister_temp_file (struct temp_dir *dir,
382                       const char *absolute_file_name)
383 {
384   struct tempdir *tmpdir = (struct tempdir *)dir;
385   gl_list_t list = tmpdir->files;
386   gl_list_node_t node;
387
388   node = gl_list_search (list, absolute_file_name);
389   if (node != NULL)
390     {
391       char *old_string = (char *) gl_list_node_value (list, node);
392
393       gl_list_remove_node (list, node);
394       free (old_string);
395     }
396 }
397
398 /* Register the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
399    that needs to be removed before DIR can be removed.
400    Should be called before the subdirectory ABSOLUTE_DIR_NAME is created.  */
401 void
402 register_temp_subdir (struct temp_dir *dir,
403                       const char *absolute_dir_name)
404 {
405   struct tempdir *tmpdir = (struct tempdir *)dir;
406
407   /* Add absolute_dir_name to tmpdir->subdirs, without duplicates.  */
408   if (gl_list_search (tmpdir->subdirs, absolute_dir_name) == NULL)
409     gl_list_add_first (tmpdir->subdirs, xstrdup (absolute_dir_name));
410 }
411
412 /* Unregister the given ABSOLUTE_DIR_NAME as being a subdirectory inside DIR,
413    that needs to be removed before DIR can be removed.
414    Should be called when the subdirectory ABSOLUTE_DIR_NAME could not be
415    created.  */
416 void
417 unregister_temp_subdir (struct temp_dir *dir,
418                         const char *absolute_dir_name)
419 {
420   struct tempdir *tmpdir = (struct tempdir *)dir;
421   gl_list_t list = tmpdir->subdirs;
422   gl_list_node_t node;
423
424   node = gl_list_search (list, absolute_dir_name);
425   if (node != NULL)
426     {
427       char *old_string = (char *) gl_list_node_value (list, node);
428
429       gl_list_remove_node (list, node);
430       free (old_string);
431     }
432 }
433
434 /* Remove a file, with optional error message.
435    Return 0 upon success, or -1 if there was some problem.  */
436 static int
437 do_unlink (struct temp_dir *dir, const char *absolute_file_name)
438 {
439   if (unlink (absolute_file_name) < 0 && dir->cleanup_verbose
440       && errno != ENOENT)
441     {
442       error (0, errno, _("cannot remove temporary file %s"), absolute_file_name);
443       return -1;
444     }
445   return 0;
446 }
447
448 /* Remove a directory, with optional error message.
449    Return 0 upon success, or -1 if there was some problem.  */
450 static int
451 do_rmdir (struct temp_dir *dir, const char *absolute_dir_name)
452 {
453   if (rmdir (absolute_dir_name) < 0 && dir->cleanup_verbose
454       && errno != ENOENT)
455     {
456       error (0, errno,
457              _("cannot remove temporary directory %s"), absolute_dir_name);
458       return -1;
459     }
460   return 0;
461 }
462
463 /* Remove the given ABSOLUTE_FILE_NAME and unregister it.
464    Return 0 upon success, or -1 if there was some problem.  */
465 int
466 cleanup_temp_file (struct temp_dir *dir,
467                    const char *absolute_file_name)
468 {
469   int err;
470
471   err = do_unlink (dir, absolute_file_name);
472   unregister_temp_file (dir, absolute_file_name);
473
474   return err;
475 }
476
477 /* Remove the given ABSOLUTE_DIR_NAME and unregister it.
478    Return 0 upon success, or -1 if there was some problem.  */
479 int
480 cleanup_temp_subdir (struct temp_dir *dir,
481                      const char *absolute_dir_name)
482 {
483   int err;
484
485   err = do_rmdir (dir, absolute_dir_name);
486   unregister_temp_subdir (dir, absolute_dir_name);
487
488   return err;
489 }
490
491 /* Remove all registered files and subdirectories inside DIR.
492    Return 0 upon success, or -1 if there was some problem.  */
493 int
494 cleanup_temp_dir_contents (struct temp_dir *dir)
495 {
496   struct tempdir *tmpdir = (struct tempdir *)dir;
497   int err = 0;
498   gl_list_t list;
499   gl_list_iterator_t iter;
500   const void *element;
501   gl_list_node_t node;
502
503   /* First cleanup the files in the subdirectories.  */
504   list = tmpdir->files;
505   iter = gl_list_iterator (list);
506   while (gl_list_iterator_next (&iter, &element, &node))
507     {
508       char *file = (char *) element;
509
510       err |= do_unlink (dir, file);
511       gl_list_remove_node (list, node);
512       /* Now only we can free file.  */
513       free (file);
514     }
515   gl_list_iterator_free (&iter);
516
517   /* Then cleanup the subdirectories.  */
518   list = tmpdir->subdirs;
519   iter = gl_list_iterator (list);
520   while (gl_list_iterator_next (&iter, &element, &node))
521     {
522       char *subdir = (char *) element;
523
524       err |= do_rmdir (dir, subdir);
525       gl_list_remove_node (list, node);
526       /* Now only we can free subdir.  */
527       free (subdir);
528     }
529   gl_list_iterator_free (&iter);
530
531   return err;
532 }
533
534 /* Remove all registered files and subdirectories inside DIR and DIR itself.
535    DIR cannot be used any more after this call.
536    Return 0 upon success, or -1 if there was some problem.  */
537 int
538 cleanup_temp_dir (struct temp_dir *dir)
539 {
540   struct tempdir *tmpdir = (struct tempdir *)dir;
541   int err = 0;
542   size_t i;
543
544   err |= cleanup_temp_dir_contents (dir);
545   err |= do_rmdir (dir, tmpdir->dirname);
546
547   for (i = 0; i < cleanup_list.tempdir_count; i++)
548     if (cleanup_list.tempdir_list[i] == tmpdir)
549       {
550         /* Remove cleanup_list.tempdir_list[i].  */
551         if (i + 1 == cleanup_list.tempdir_count)
552           {
553             while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
554               i--;
555             cleanup_list.tempdir_count = i;
556           }
557         else
558           cleanup_list.tempdir_list[i] = NULL;
559         /* Now only we can free the tmpdir->dirname, tmpdir->subdirs,
560            tmpdir->files, and tmpdir itself.  */
561         gl_list_free (tmpdir->files);
562         gl_list_free (tmpdir->subdirs);
563         free (tmpdir->dirname);
564         free (tmpdir);
565         return err;
566       }
567
568   /* The user passed an invalid DIR argument.  */
569   abort ();
570 }
571
572
573 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
574
575 /* On Windows, opening a file with _O_TEMPORARY has the effect of passing
576    the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect
577    of deleting the file when it is closed - even when the program crashes.
578    But (according to the Cygwin sources) it works only on Windows NT or newer.
579    So we cache the info whether we are running on Windows NT or newer.  */
580
581 static bool
582 supports_delete_on_close ()
583 {
584   static int known; /* 1 = yes, -1 = no, 0 = unknown */
585   /* M4 wants to close and later reopen a temporary file, so
586      delete-on-close must not be used.  */
587   known = -1;
588   if (!known)
589     {
590       OSVERSIONINFO v;
591
592       /* According to
593          <http://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx>
594          this structure must be initialised as follows:  */
595       v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
596
597       if (GetVersionEx (&v))
598         known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
599       else
600         known = -1;
601     }
602   return (known > 0);
603 }
604
605 #endif
606
607
608 /* Register a file descriptor to be closed.  */
609 static void
610 register_fd (int fd)
611 {
612   if (descriptors == NULL)
613     descriptors = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, NULL,
614                                         false);
615   gl_list_add_first (descriptors, (void *) (uintptr_t) fd);
616 }
617
618 /* Unregister a file descriptor to be closed.  */
619 static void
620 unregister_fd (int fd)
621 {
622   gl_list_t fds = descriptors;
623   gl_list_node_t node;
624
625   if (fds == NULL)
626     /* descriptors should already contain fd.  */
627     abort ();
628   node = gl_list_search (fds, (void *) (uintptr_t) fd);
629   if (node == NULL)
630     /* descriptors should already contain fd.  */
631     abort ();
632   gl_list_remove_node (fds, node);
633 }
634
635 /* Open a temporary file in a temporary directory.
636    Registers the resulting file descriptor to be closed.  */
637 int
638 open_temp (const char *file_name, int flags, mode_t mode)
639 {
640   int fd;
641   int saved_errno;
642
643   block_fatal_signals ();
644   /* Note: 'open' here is actually open() or open_safer().  */
645 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
646   /* Use _O_TEMPORARY when possible, to increase the chances that the
647      temporary file is removed when the process crashes.  */
648   if (supports_delete_on_close ())
649     fd = open (file_name, flags | _O_TEMPORARY, mode);
650   else
651 #endif
652     fd = open (file_name, flags, mode);
653   saved_errno = errno;
654   if (fd >= 0)
655     register_fd (fd);
656   unblock_fatal_signals ();
657   errno = saved_errno;
658   return fd;
659 }
660
661 /* Open a temporary file in a temporary directory.
662    Registers the resulting file descriptor to be closed.  */
663 FILE *
664 fopen_temp (const char *file_name, const char *mode)
665 {
666   FILE *fp;
667   int saved_errno;
668
669   block_fatal_signals ();
670   /* Note: 'fopen' here is actually fopen() or fopen_safer().  */
671 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
672   /* Use _O_TEMPORARY when possible, to increase the chances that the
673      temporary file is removed when the process crashes.  */
674   if (supports_delete_on_close ())
675     {
676       size_t mode_len = strlen (mode);
677       char *augmented_mode = (char *) xmalloca (mode_len + 2);
678       memcpy (augmented_mode, mode, mode_len);
679       memcpy (augmented_mode + mode_len, "D", 2);
680
681       fp = fopen (file_name, augmented_mode);
682       saved_errno = errno;
683
684       freea (augmented_mode);
685     }
686   else
687 #endif
688     {
689       fp = fopen (file_name, mode);
690       saved_errno = errno;
691     }
692   if (fp != NULL)
693     {
694       /* It is sufficient to register fileno (fp) instead of the entire fp,
695          because at cleanup time there is no need to do an fflush (fp); a
696          close (fileno (fp)) will be enough.  */
697       int fd = fileno (fp);
698       if (!(fd >= 0))
699         abort ();
700       register_fd (fd);
701     }
702   unblock_fatal_signals ();
703   errno = saved_errno;
704   return fp;
705 }
706
707 /* Close a temporary file in a temporary directory.
708    Unregisters the previously registered file descriptor.  */
709 int
710 close_temp (int fd)
711 {
712   if (fd >= 0)
713     {
714       /* No blocking of signals is needed here, since a double close of a
715          file descriptor is harmless.  */
716       int result = close (fd);
717       int saved_errno = errno;
718
719       /* No race condition here: we assume a single-threaded program, hence
720          fd cannot be re-opened here.  */
721
722       unregister_fd (fd);
723
724       errno = saved_errno;
725       return result;
726     }
727   else
728     return close (fd);
729 }
730
731 /* Close a temporary file in a temporary directory.
732    Unregisters the previously registered file descriptor.  */
733 int
734 fclose_temp (FILE *fp)
735 {
736   int fd = fileno (fp);
737   /* No blocking of signals is needed here, since a double close of a
738      file descriptor is harmless.  */
739   int result = fclose (fp);
740   int saved_errno = errno;
741
742   /* No race condition here: we assume a single-threaded program, hence
743      fd cannot be re-opened here.  */
744
745   unregister_fd (fd);
746
747   errno = saved_errno;
748   return result;
749 }
750
751 #if GNULIB_FWRITEERROR
752 /* Like fwriteerror.
753    Unregisters the previously registered file descriptor.  */
754 int
755 fwriteerror_temp (FILE *fp)
756 {
757   int fd = fileno (fp);
758   /* No blocking of signals is needed here, since a double close of a
759      file descriptor is harmless.  */
760   int result = fwriteerror (fp);
761   int saved_errno = errno;
762
763   /* No race condition here: we assume a single-threaded program, hence
764      fd cannot be re-opened here.  */
765
766   unregister_fd (fd);
767
768   errno = saved_errno;
769   return result;
770 }
771 #endif
772
773 #if GNULIB_CLOSE_STREAM
774 /* Like close_stream.
775    Unregisters the previously registered file descriptor.  */
776 int
777 close_stream_temp (FILE *fp)
778 {
779   int fd = fileno (fp);
780   /* No blocking of signals is needed here, since a double close of a
781      file descriptor is harmless.  */
782   int result = close_stream (fp);
783   int saved_errno = errno;
784
785   /* No race condition here: we assume a single-threaded program, hence
786      fd cannot be re-opened here.  */
787
788   unregister_fd (fd);
789
790   errno = saved_errno;
791   return result;
792 }
793 #endif