m4-commit
[Top][All Lists]
Advanced

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

Changes to m4/src/Attic/output.c,v [branch-1_4]


From: Eric Blake
Subject: Changes to m4/src/Attic/output.c,v [branch-1_4]
Date: Mon, 13 Nov 2006 23:25:09 +0000

CVSROOT:        /sources/m4
Module name:    m4
Branch:         branch-1_4
Changes by:     Eric Blake <ericb>      06/11/13 23:25:08

Index: src/output.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/output.c,v
retrieving revision 1.1.1.1.2.16
retrieving revision 1.1.1.1.2.17
diff -u -b -r1.1.1.1.2.16 -r1.1.1.1.2.17
--- src/output.c        13 Nov 2006 19:10:57 -0000      1.1.1.1.2.16
+++ src/output.c        13 Nov 2006 23:25:08 -0000      1.1.1.1.2.17
@@ -21,6 +21,7 @@
 
 #include "m4.h"
 
+#include <limits.h>
 #include <sys/stat.h>
 
 #include "gl_avltree_oset.h"
@@ -47,8 +48,9 @@
 /* When part of diversion_table, each struct m4_diversion either
    represents an open file (zero size, non-NULL u.file), an in-memory
    buffer (non-zero size, non-NULL u.buffer), or an unused placeholder
-   diversion (zero size, u is NULL).  When not part of
-   diversion_table, u.next is a pointer to the free_list chain.  */
+   diversion (zero size, u is NULL, non-zero used indicates that a
+   file has been created).  When not part of diversion_table, u.next
+   is a pointer to the free_list chain.  */
 
 typedef struct m4_diversion m4_diversion;
 
@@ -180,16 +182,32 @@
     _exit (exit_failure);
 }
 
-/* Create a temporary file open for reading and writing in a secure
-   temp directory.  The file will be automatically closed and deleted
-   on a fatal signal.  When done with the file, close it with
-   close_stream_temp.  Exits on failure, so the return value is always
-   an open file.  */
+/* Convert DIVNUM into a temporary file name for use in m4_tmp*.  */
+static const char *
+m4_tmpname (int divnum)
+{
+  static char *buffer;
+  static char *tail;
+  if (buffer == NULL)
+    {
+      tail = xasprintf ("%s/m4-%d", output_temp_dir->dir_name, INT_MAX);
+      buffer = obstack_copy0 (&diversion_storage, tail, strlen (tail));
+      tail = strrchr (buffer, '-') + 1;
+    }
+  sprintf (tail, "%d", divnum);
+  return buffer;
+}
+
+/* Create a temporary file for diversion DIVNUM open for reading and
+   writing in a secure temp directory.  The file will be automatically
+   closed and deleted on a fatal signal.  The file can be closed and
+   reopened with m4_tmpclose and m4_tmpopen; when finally done with
+   the file, close it with m4_tmpremove.  Exits on failure, so the
+   return value is always an open file.  */
 static FILE *
-m4_tmpfile (void)
+m4_tmpfile (int divnum)
 {
-  static unsigned int count;
-  char *name;
+  const char *name;
   FILE *file;
 
   if (output_temp_dir == NULL)
@@ -201,17 +219,56 @@
                  "cannot create temporary file for diversion"));
       atexit (cleanup_tmpfile);
     }
-  name = xasprintf ("%s/m4-%d", output_temp_dir->dir_name, count++);
+  name = m4_tmpname (divnum);
   register_temp_file (output_temp_dir, name);
   errno = 0;
   file = fopen_temp (name, O_BINARY ? "wb+" : "w+");
   if (file == NULL)
+    {
+      unregister_temp_file (output_temp_dir, name);
     M4ERROR ((EXIT_FAILURE, errno,
              "cannot create temporary file for diversion"));
-  free (name);
+    }
+  else if (set_cloexec_flag (fileno (file), true) != 0)
+    M4ERROR ((warning_status, errno,
+             "Warning: cannot protect diversion across forks"));
   return file;
 }
 
+/* Reopen a temporary file for diversion DIVNUM for reading and
+   writing in a secure temp directory.  Exits on failure, so the
+   return value is always an open file.  */
+static FILE *
+m4_tmpopen (int divnum)
+{
+  const char *name = m4_tmpname (divnum);
+  FILE *file;
+
+  errno = 0;
+  file = fopen_temp (name, O_BINARY ? "ab+" : "a+");
+  if (file == NULL)
+    M4ERROR ((EXIT_FAILURE, errno,
+             "cannot create temporary file for diversion"));
+  else if (set_cloexec_flag (fileno (file), true) != 0)
+    M4ERROR ((warning_status, errno,
+             "Warning: cannot protect diversion across forks"));
+  return file;
+}
+
+/* Close, but don't delete, a temporary FILE.  */
+static int
+m4_tmpclose (FILE *file)
+{
+  return close_stream_temp (file);
+}
+
+/* Delete a closed temporary FILE for diversion DIVNUM.  */
+static int
+m4_tmpremove (int divnum)
+{
+  return cleanup_temp_file (output_temp_dir, m4_tmpname (divnum));
+}
+
 /*-----------------------------------------------------------------------.
 | Reorganize in-memory diversion buffers so the current diversion can   |
 | accomodate LENGTH more characters without further reorganization.  The |
@@ -280,11 +337,7 @@
       total_buffer_size -= selected_diversion->size;
       selected_diversion->size = 0;
       selected_diversion->u.file = NULL;
-      selected_diversion->u.file = m4_tmpfile ();
-
-      if (set_cloexec_flag (fileno (selected_diversion->u.file), true) != 0)
-       M4ERROR ((warning_status, errno,
-                 "Warning: cannot protect diversion across forks"));
+      selected_diversion->u.file = m4_tmpfile (selected_diversion->divnum);
 
       if (selected_diversion->used > 0)
        {
@@ -298,7 +351,7 @@
       /* Reclaim the buffer space for other diversions.  */
 
       free (selected_buffer);
-      selected_diversion->used = 0;
+      selected_diversion->used = 1;
     }
 
   /* Reload output_file, just in case the flushed diversion was current.  */
@@ -313,8 +366,16 @@
     }
   else
     {
-      /* The buffer may be safely reallocated.  */
+      /* Close any selected file since it is not the current diversion.  */
+      if (selected_diversion)
+       {
+         FILE *file = selected_diversion->u.file;
+         selected_diversion->u.file = 0;
+         if (m4_tmpclose (file) != 0)
+           M4ERROR ((0, errno, "cannot close temporary file for diversion"));
+       }
 
+      /* The current buffer may be safely reallocated.  */
       output_diversion->u.buffer
        = xrealloc (output_diversion->u.buffer, (size_t) wanted_size);
 
@@ -501,10 +562,18 @@
          if (!gl_oset_remove (diversion_table, output_diversion))
            error (EXIT_FAILURE, 0, "INTERNAL ERROR: make_diversion failed");
          output_diversion->u.next = free_list;
+         output_diversion->used = 0;
          free_list = output_diversion;
        }
-      else
+      else if (output_diversion->size)
        output_diversion->used = output_diversion->size - output_unused;
+      else if (output_diversion->used)
+       {
+         FILE *file = output_diversion->u.file;
+         output_diversion->u.file = NULL;
+         if (m4_tmpclose (file) != 0)
+           M4ERROR ((0, errno, "cannot close temporary file for diversion"));
+       }
       output_diversion = NULL;
       output_file = NULL;
       output_cursor = NULL;
@@ -556,7 +625,11 @@
       output_unused = output_diversion->size - output_diversion->used;
     }
   else
+    {
+      if (!output_diversion->u.file && output_diversion->used)
+       output_diversion->u.file = m4_tmpopen (output_diversion->divnum);
     output_file = output_diversion->u.file;
+    }
   output_current_line = -1;
 }
 
@@ -605,11 +678,16 @@
     {
       if (diversion->size)
        output_text (diversion->u.buffer, diversion->used);
-      else if (diversion->u.file)
+      else
+       {
+         if (!diversion->u.file && diversion->used)
+           diversion->u.file = m4_tmpopen (diversion->divnum);
+         if (diversion->u.file)
        {
          rewind (diversion->u.file);
          insert_file (diversion->u.file);
        }
+       }
 
       output_current_line = -1;
     }
@@ -621,8 +699,19 @@
       diversion->size = 0;
       diversion->used = 0;
     }
-  else if (diversion->u.file && close_stream_temp (diversion->u.file) != 0)
+  else
+    {
+      if (diversion->u.file)
+       {
+         FILE *file = diversion->u.file;
+         diversion->u.file = NULL;
+         diversion->used = 0;
+         if (m4_tmpclose (file) != 0)
     M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+       }
+      if (m4_tmpremove (diversion->divnum) != 0)
+       M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+    }
   gl_oset_remove (diversion_table, diversion);
   diversion->u.next = free_list;
   free_list = diversion;




reply via email to

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