(root)/
m4-1.4.19/
tests/
read-file.c
       1  /* read-file.c -- read file contents into a string
       2     Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
       3     Written by Simon Josefsson and Bruno Haible.
       4  
       5     This program is free software; you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation; either version 3, or (at your option)
       8     any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <config.h>
      19  
      20  #include "read-file.h"
      21  
      22  /* Get fstat.  */
      23  #include <sys/stat.h>
      24  
      25  /* Get ftello.  */
      26  #include <stdio.h>
      27  
      28  /* Get PTRDIFF_MAX.  */
      29  #include <stdint.h>
      30  
      31  /* Get malloc, realloc, free. */
      32  #include <stdlib.h>
      33  
      34  /* Get explicit_bzero, memcpy. */
      35  #include <string.h>
      36  
      37  /* Get errno. */
      38  #include <errno.h>
      39  
      40  /* Read a STREAM and return a newly allocated string with the content,
      41     and set *LENGTH to the length of the string.  The string is
      42     zero-terminated, but the terminating zero byte is not counted in
      43     *LENGTH.  On errors, *LENGTH is undefined, errno preserves the
      44     values set by system functions (if any), and NULL is returned.
      45  
      46     If the RF_SENSITIVE flag is set in FLAGS:
      47       - You should control the buffering of STREAM using 'setvbuf'.  Either
      48         clear the buffer of STREAM after closing it, or disable buffering of
      49         STREAM before calling this function.
      50       - The memory buffer internally allocated will be cleared upon failure.  */
      51  char *
      52  fread_file (FILE *stream, int flags, size_t *length)
      53  {
      54    char *buf = NULL;
      55    size_t alloc = BUFSIZ;
      56  
      57    /* For a regular file, allocate a buffer that has exactly the right
      58       size.  This avoids the need to do dynamic reallocations later.  */
      59    {
      60      struct stat st;
      61  
      62      if (fstat (fileno (stream), &st) >= 0 && S_ISREG (st.st_mode))
      63        {
      64          off_t pos = ftello (stream);
      65  
      66          if (pos >= 0 && pos < st.st_size)
      67            {
      68              off_t alloc_off = st.st_size - pos;
      69  
      70              /* '1' below, accounts for the trailing NUL.  */
      71              if (PTRDIFF_MAX - 1 < alloc_off)
      72                {
      73                  errno = ENOMEM;
      74                  return NULL;
      75                }
      76  
      77              alloc = alloc_off + 1;
      78            }
      79        }
      80    }
      81  
      82    if (!(buf = malloc (alloc)))
      83      return NULL; /* errno is ENOMEM.  */
      84  
      85    {
      86      size_t size = 0; /* number of bytes read so far */
      87      int save_errno;
      88  
      89      for (;;)
      90        {
      91          /* This reads 1 more than the size of a regular file
      92             so that we get eof immediately.  */
      93          size_t requested = alloc - size;
      94          size_t count = fread (buf + size, 1, requested, stream);
      95          size += count;
      96  
      97          if (count != requested)
      98            {
      99              save_errno = errno;
     100              if (ferror (stream))
     101                break;
     102  
     103              /* Shrink the allocated memory if possible.  */
     104              if (size < alloc - 1)
     105                {
     106                  if (flags & RF_SENSITIVE)
     107                    {
     108                      char *smaller_buf = malloc (size + 1);
     109                      if (smaller_buf == NULL)
     110                        explicit_bzero (buf + size, alloc - size);
     111                      else
     112                        {
     113                          memcpy (smaller_buf, buf, size);
     114                          explicit_bzero (buf, alloc);
     115                          free (buf);
     116                          buf = smaller_buf;
     117                        }
     118                    }
     119                  else
     120                    {
     121                      char *smaller_buf = realloc (buf, size + 1);
     122                      if (smaller_buf != NULL)
     123                        buf = smaller_buf;
     124                    }
     125                }
     126  
     127              buf[size] = '\0';
     128              *length = size;
     129              return buf;
     130            }
     131  
     132          {
     133            char *new_buf;
     134            size_t save_alloc = alloc;
     135  
     136            if (alloc == PTRDIFF_MAX)
     137              {
     138                save_errno = ENOMEM;
     139                break;
     140              }
     141  
     142            if (alloc < PTRDIFF_MAX - alloc / 2)
     143              alloc = alloc + alloc / 2;
     144            else
     145              alloc = PTRDIFF_MAX;
     146  
     147            if (flags & RF_SENSITIVE)
     148              {
     149                new_buf = malloc (alloc);
     150                if (!new_buf)
     151                  {
     152                    /* BUF should be cleared below after the loop.  */
     153                    save_errno = errno;
     154                    break;
     155                  }
     156                memcpy (new_buf, buf, save_alloc);
     157                explicit_bzero (buf, save_alloc);
     158                free (buf);
     159              }
     160            else if (!(new_buf = realloc (buf, alloc)))
     161              {
     162                save_errno = errno;
     163                break;
     164              }
     165  
     166            buf = new_buf;
     167          }
     168        }
     169  
     170      if (flags & RF_SENSITIVE)
     171        explicit_bzero (buf, alloc);
     172  
     173      free (buf);
     174      errno = save_errno;
     175      return NULL;
     176    }
     177  }
     178  
     179  /* Open and read the contents of FILENAME, and return a newly
     180     allocated string with the content, and set *LENGTH to the length of
     181     the string.  The string is zero-terminated, but the terminating
     182     zero byte is not counted in *LENGTH.  On errors, *LENGTH is
     183     undefined, errno preserves the values set by system functions (if
     184     any), and NULL is returned.
     185  
     186     If the RF_BINARY flag is set in FLAGS, the file is opened in binary
     187     mode.  If the RF_SENSITIVE flag is set in FLAGS, the memory buffer
     188     internally allocated will be cleared upon failure.  */
     189  char *
     190  read_file (const char *filename, int flags, size_t *length)
     191  {
     192    const char *mode = (flags & RF_BINARY) ? "rbe" : "re";
     193    FILE *stream = fopen (filename, mode);
     194    char *out;
     195  
     196    if (!stream)
     197      return NULL;
     198  
     199    if (flags & RF_SENSITIVE)
     200      setvbuf (stream, NULL, _IONBF, 0);
     201  
     202    out = fread_file (stream, flags, length);
     203  
     204    if (fclose (stream) != 0)
     205      {
     206        if (out)
     207          {
     208            if (flags & RF_SENSITIVE)
     209              explicit_bzero (out, *length);
     210            free (out);
     211          }
     212        return NULL;
     213      }
     214  
     215    return out;
     216  }