コード例 #1
0
ファイル: path.c プロジェクト: Distrotech/m4
/* Attempt to open FILE; if it opens, verify that it is not a
   directory, and ensure it does not leak across execs.  */
FILE *
m4_fopen (m4 *context, const char *file, const char *mode)
{
  FILE *fp = NULL;

  if (file)
    {
      struct stat st;
      int fd;

      fp = fopen (file, mode);
      fd = fileno (fp);

      if (fstat (fd, &st) == 0 && S_ISDIR (st.st_mode))
        {
          fclose (fp);
          errno = EISDIR;
          return NULL;
        }
      if (set_cloexec_flag (fileno (fp), true) != 0)
        m4_error (context, 0, errno, NULL,
                  _("cannot protect input file across forks"));
    }
  return fp;
}
コード例 #2
0
ファイル: output.c プロジェクト: AaronNGray/winflexbison
/* Transfer the temporary file for diversion OLDNUM to the previously
   unused diversion NEWNUM.  Return an open stream visiting the new
   temporary file, positioned at the end, or exit on failure.  */
static FILE*
m4_tmprename (int oldnum, int newnum)
{
  /* m4_tmpname reuses its return buffer.  */
  char *oldname = xstrdup (m4_tmpname (oldnum));
  const char *newname = m4_tmpname (newnum);
  register_temp_file (output_temp_dir, newname);
  if (oldnum == tmp_file1_owner)
    {
      /* Be careful of mingw, which can't rename an open file.  */
      if (RENAME_OPEN_FILE_WORKS)
        tmp_file1_owner = newnum;
      else
        {
          if (close_stream_temp (tmp_file1))
            m4_error (EXIT_FAILURE, errno,
                      _("cannot close temporary file for diversion"));
          tmp_file1_owner = 0;
        }
    }
  else if (oldnum == tmp_file2_owner)
    {
      /* Be careful of mingw, which can't rename an open file.  */
      if (RENAME_OPEN_FILE_WORKS)
        tmp_file2_owner = newnum;
      else
        {
          if (close_stream_temp (tmp_file2))
            m4_error (EXIT_FAILURE, errno,
                      _("cannot close temporary file for diversion"));
          tmp_file2_owner = 0;
        }
    }
  /* Either it is safe to rename an open file, or no one should have
     oldname open at this point.  */
  if (rename (oldname, newname))
    m4_error (EXIT_FAILURE, errno,
              _("cannot create temporary file for diversion"));
  unregister_temp_file (output_temp_dir, oldname);
  free (oldname);
  return m4_tmpopen (newnum, false);
}
コード例 #3
0
ファイル: output.c プロジェクト: AaronNGray/winflexbison
/* Reopen a temporary file for diversion DIVNUM for reading and
   writing in a secure temp directory.  If REREAD, the file is
   positioned at offset 0, otherwise the file is positioned at the
   end.  Exits on failure, so the return value is always an open
   file.  */
static FILE *
m4_tmpopen (int divnum, bool reread)
{
  const char *name;
  FILE *file;

  if (tmp_file1_owner == divnum)
    {
      if (reread && fseek (tmp_file1, 0, SEEK_SET) != 0)
        m4_error (EXIT_FAILURE, errno,
                  _("cannot seek within diversion"));
      tmp_file2_recent = false;
      return tmp_file1;
    }
  else if (tmp_file2_owner == divnum)
    {
      if (reread && fseek (tmp_file2, 0, SEEK_SET) != 0)
        m4_error (EXIT_FAILURE, errno,
                  _("cannot seek within diversion"));
      tmp_file2_recent = true;
      return tmp_file2;
    }
  name = m4_tmpname (divnum);
  /* We need update mode, to avoid truncation.  */
  file = fopen_temp (name, O_BINARY ? "rb+" : "r+");
  if (file == NULL)
    M4ERROR ((EXIT_FAILURE, errno,
              "cannot create temporary file for diversion"));
//  else if (set_cloexec_flag (fileno (file), true) != 0)
//    m4_error (0, errno, _("cannot protect diversion across forks"));
  /* Update mode starts at the beginning of the stream, but sometimes
     we want the end.  */
  else if (!reread && fseek (file, 0, SEEK_END) != 0)
    m4_error (EXIT_FAILURE, errno,
              _("cannot seek within diversion"));
  return file;
}
コード例 #4
0
ファイル: debug.c プロジェクト: Distrotech/m4
/* Change the debug output stream to FP.  If the underlying file is the
   same as stdout, use stdout instead so that debug messages appear in the
   correct relative position.  Report errors on behalf of CALLER.  */
static void
set_debug_file (m4 *context, const m4_call_info *caller, FILE *fp)
{
  FILE *debug_file;
  struct stat stdout_stat, debug_stat;

  assert (context);

  debug_file = m4_get_debug_file (context);
  if (debug_file != NULL && debug_file != stderr && debug_file != stdout
      && close_stream (debug_file) != 0)
    m4_error (context, 0, errno, caller, _("error writing to debug stream"));

  debug_file = fp;
  m4_set_debug_file (context, fp);

  if (debug_file != NULL && debug_file != stdout)
    {
      if (fstat (fileno (stdout), &stdout_stat) < 0)
        return;
      if (fstat (fileno (debug_file), &debug_stat) < 0)
        return;

      /* mingw has a bug where fstat on a regular file reports st_ino
         of 0.  On normal system, st_ino should never be 0.  */
      if (stdout_stat.st_ino == debug_stat.st_ino
          && stdout_stat.st_dev == debug_stat.st_dev
          && stdout_stat.st_ino != 0)
        {
          if (debug_file != stderr && close_stream (debug_file) != 0)
            m4_error (context, 0, errno, caller,
                      _("error writing to debug stream"));
          m4_set_debug_file (context, stdout);
        }
    }
}
コード例 #5
0
ファイル: path.c プロジェクト: Distrotech/m4
/* Generic load function.  Push the input file or load the module named
   FILENAME, if it can be found in the search path.  Complain
   about inaccesible files iff SILENT is false.  */
bool
m4_load_filename (m4 *context, const m4_call_info *caller,
	          const char *filename, m4_obstack *obs, bool silent)
{
  char *filepath = NULL;
  char *suffix   = NULL;
  bool new_input = false;

  if (m4_get_posixly_correct_opt (context))
    {
      if (access (filename, R_OK) == 0)
        filepath = xstrdup (filename);
    }
  else
    filepath = m4_path_search (context, filename, FILE_SUFFIXES);

  if (filepath)
    suffix = strrchr (filepath, '.');

  if (!m4_get_posixly_correct_opt (context)
      && suffix
      && STREQ (suffix, LT_MODULE_EXT))
    {
      m4_module_load (context, filename, obs);
    }
  else
    {
      FILE *fp = NULL;

      if (filepath)
        fp = m4_fopen (context, filepath, "r");

      if (fp == NULL)
        {
          if (!silent)
	    m4_error (context, 0, errno, caller, _("cannot open file '%s'"),
		      filename);
          free (filepath);
          return false;
        }

      m4_push_file (context, fp, filepath, true);
      new_input = true;
    }
  free (filepath);

  return new_input;
}
コード例 #6
0
ファイル: output.c プロジェクト: AaronNGray/winflexbison
static void
insert_diversion_helper (m4_diversion *diversion)
{
  /* Effectively undivert only if an output stream is active.  */
  if (output_diversion)
    {
      if (diversion->size)
        {
          if (!output_diversion->u.file)
            {
              /* Transferring diversion metadata is faster than
                 copying contents.  */
              assert (!output_diversion->used && output_diversion != &div0
                      && !output_file);
              output_diversion->u.buffer = diversion->u.buffer;
              output_diversion->size = diversion->size;
              output_cursor = diversion->u.buffer + diversion->used;
              output_unused = diversion->size - diversion->used;
              diversion->u.buffer = NULL;
            }
          else
            {
              /* Avoid double-charging the total in-memory size when
                 transferring from one in-memory diversion to
                 another.  */
              total_buffer_size -= diversion->size;
              output_text (diversion->u.buffer, diversion->used);
            }
        }
      else if (!output_diversion->u.file)
        {
          /* Transferring diversion metadata is faster than copying
             contents.  */
          assert (!output_diversion->used && output_diversion != &div0
                  && !output_file);
          output_diversion->u.file = m4_tmprename (diversion->divnum,
                                                   output_diversion->divnum);
          output_diversion->used = 1;
          output_file = output_diversion->u.file;
          diversion->u.file = NULL;
          diversion->size = 1;
        }
      else
        {
          if (!diversion->u.file)
            diversion->u.file = m4_tmpopen (diversion->divnum, true);
          insert_file (diversion->u.file);
        }

      output_current_line = -1;
    }

  /* Return all space used by the diversion.  */
  if (diversion->size)
    {
      if (!output_diversion)
        total_buffer_size -= diversion->size;
      free (diversion->u.buffer);
      diversion->size = 0;
    }
  else
    {
      if (diversion->u.file)
        {
          FILE *file = diversion->u.file;
          diversion->u.file = NULL;
          if (m4_tmpclose (file, diversion->divnum) != 0)
            m4_error (0, errno,
                      _("cannot clean temporary file for diversion"));
        }
      if (m4_tmpremove (diversion->divnum) != 0)
        M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
    }
  diversion->used = 0;
  gl_oset_remove (diversion_table, diversion);
  diversion->u.next = free_list;
  free_list = diversion;
}
コード例 #7
0
ファイル: output.c プロジェクト: AaronNGray/winflexbison
void
make_diversion (int divnum)
{
  m4_diversion *diversion = NULL;

  if (current_diversion == divnum)
    return;

  if (output_diversion)
    {
      if (!output_diversion->size && !output_diversion->u.file)
        {
          assert (!output_diversion->used);
          if (!gl_oset_remove (diversion_table, output_diversion))
            assert (false);
          output_diversion->u.next = free_list;
          free_list = output_diversion;
        }
      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, output_diversion->divnum) != 0)
            m4_error (0, errno,
                      _("cannot close temporary file for diversion"));
        }
      output_diversion = NULL;
      output_file = NULL;
      output_cursor = NULL;
      output_unused = 0;
    }

  current_diversion = divnum;

  if (divnum < 0)
    return;

  if (divnum == 0)
    diversion = &div0;
  else
    {
      const void *elt;
      if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB,
                                  &divnum, &elt))
        {
          m4_diversion *temp = (m4_diversion *) elt;
          if (temp->divnum == divnum)
            diversion = temp;
        }
    }
  if (diversion == NULL)
    {
      /* First time visiting this diversion.  */
      if (free_list)
        {
          diversion = free_list;
          free_list = diversion->u.next;
        }
      else
        {
          diversion = (m4_diversion *) obstack_alloc (&diversion_storage,
                                                      sizeof *diversion);
          diversion->size = 0;
          diversion->used = 0;
        }
      diversion->u.file = NULL;
      diversion->divnum = divnum;
      gl_oset_add (diversion_table, diversion);
    }

  output_diversion = diversion;
  if (output_diversion->size)
    {
      output_cursor = output_diversion->u.buffer + output_diversion->used;
      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,
                                               false);
      output_file = output_diversion->u.file;
    }
  output_current_line = -1;
}
コード例 #8
0
ファイル: output.c プロジェクト: AaronNGray/winflexbison
static void
make_room_for (int length)
{
  int wanted_size;
  m4_diversion *selected_diversion = NULL;

  /* Compute needed size for in-memory buffer.  Diversions in-memory
     buffers start at 0 bytes, then 512, then keep doubling until it is
     decided to flush them to disk.  */

  output_diversion->used = output_diversion->size - output_unused;

  for (wanted_size = output_diversion->size;
       wanted_size < output_diversion->used + length;
       wanted_size = wanted_size == 0 ? INITIAL_BUFFER_SIZE : wanted_size * 2)
    ;

  /* Check if we are exceeding the maximum amount of buffer memory.  */

  if (total_buffer_size - output_diversion->size + wanted_size
      > MAXIMUM_TOTAL_SIZE)
    {
      int selected_used;
      char *selected_buffer;
      m4_diversion *diversion;
      int count;
      gl_oset_iterator_t iter;
      const void *elt;

      /* Find out the buffer having most data, in view of flushing it to
         disk.  Fake the current buffer as having already received the
         projected data, while making the selection.  So, if it is
         selected indeed, we will flush it smaller, before it grows.  */

      selected_diversion = output_diversion;
      selected_used = output_diversion->used + length;

      iter = gl_oset_iterator (diversion_table);
      while (gl_oset_iterator_next (&iter, &elt))
        {
          diversion = (m4_diversion *) elt;
          if (diversion->used > selected_used)
            {
              selected_diversion = diversion;
              selected_used = diversion->used;
            }
        }
      gl_oset_iterator_free (&iter);

      /* Create a temporary file, write the in-memory buffer of the
         diversion to this file, then release the buffer.  Zero the
         diversion before doing anything that can exit () (including
         m4_tmpfile), so that the atexit handler doesn't try to close
         a garbage pointer as a file.  */

      selected_buffer = selected_diversion->u.buffer;
      total_buffer_size -= selected_diversion->size;
      selected_diversion->size = 0;
      selected_diversion->u.file = NULL;
      selected_diversion->u.file = m4_tmpfile (selected_diversion->divnum);

      if (selected_diversion->used > 0)
        {
          count = fwrite (selected_buffer, (size_t) selected_diversion->used,
                          1, selected_diversion->u.file);
          if (count != 1)
            M4ERROR ((EXIT_FAILURE, errno,
                      "ERROR: cannot flush diversion to temporary file"));
        }

      /* Reclaim the buffer space for other diversions.  */

      free (selected_buffer);
      selected_diversion->used = 1;
    }

  /* Reload output_file, just in case the flushed diversion was current.  */

  if (output_diversion == selected_diversion)
    {
      /* The flushed diversion was current indeed.  */

      output_file = output_diversion->u.file;
      output_cursor = NULL;
      output_unused = 0;
    }
  else
    {
      /* Close any selected file since it is not the current diversion.  */
      if (selected_diversion)
        {
          FILE *file = selected_diversion->u.file;
          selected_diversion->u.file = NULL;
          if (m4_tmpclose (file, selected_diversion->divnum) != 0)
            m4_error (0, errno,
                      _("cannot close temporary file for diversion"));
        }

      /* The current buffer may be safely reallocated.  */
      {
        char *buffer = output_diversion->u.buffer;
        output_diversion->u.buffer = xcharalloc ((size_t) wanted_size);
        memcpy (output_diversion->u.buffer, buffer, output_diversion->used);
        free (buffer);
      }

      total_buffer_size += wanted_size - output_diversion->size;
      output_diversion->size = wanted_size;

      output_cursor = output_diversion->u.buffer + output_diversion->used;
      output_unused = wanted_size - output_diversion->used;
    }
}