Blame src/gl/read-file.c

Packit aea12f
/* read-file.c -- read file contents into a string
Packit Service 991b93
   Copyright (C) 2006, 2009-2020 Free Software Foundation, Inc.
Packit aea12f
   Written by Simon Josefsson and Bruno Haible.
Packit aea12f
Packit aea12f
   This program is free software; you can redistribute it and/or modify
Packit aea12f
   it under the terms of the GNU General Public License as published by
Packit aea12f
   the Free Software Foundation; either version 3, or (at your option)
Packit aea12f
   any later version.
Packit aea12f
Packit aea12f
   This program is distributed in the hope that it will be useful,
Packit aea12f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit aea12f
   GNU General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public License
Packit aea12f
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
#include <config.h>
Packit aea12f
Packit aea12f
#include "read-file.h"
Packit aea12f
Packit aea12f
/* Get fstat.  */
Packit aea12f
#include <sys/stat.h>
Packit aea12f
Packit aea12f
/* Get ftello.  */
Packit aea12f
#include <stdio.h>
Packit aea12f
Packit Service 991b93
/* Get PTRDIFF_MAX.  */
Packit aea12f
#include <stdint.h>
Packit aea12f
Packit aea12f
/* Get malloc, realloc, free. */
Packit aea12f
#include <stdlib.h>
Packit aea12f
Packit Service 991b93
/* Get explicit_bzero, memcpy. */
Packit Service 991b93
#include <string.h>
Packit Service 991b93
Packit aea12f
/* Get errno. */
Packit aea12f
#include <errno.h>
Packit aea12f
Packit aea12f
/* Read a STREAM and return a newly allocated string with the content,
Packit aea12f
   and set *LENGTH to the length of the string.  The string is
Packit aea12f
   zero-terminated, but the terminating zero byte is not counted in
Packit aea12f
   *LENGTH.  On errors, *LENGTH is undefined, errno preserves the
Packit Service 991b93
   values set by system functions (if any), and NULL is returned.
Packit Service 991b93
Packit Service 991b93
   If the RF_SENSITIVE flag is set in FLAGS:
Packit Service 991b93
     - You should control the buffering of STREAM using 'setvbuf'.  Either
Packit Service 991b93
       clear the buffer of STREAM after closing it, or disable buffering of
Packit Service 991b93
       STREAM before calling this function.
Packit Service 991b93
     - The memory buffer internally allocated will be cleared upon failure.  */
Packit aea12f
char *
Packit Service 991b93
fread_file (FILE *stream, int flags, size_t *length)
Packit aea12f
{
Packit aea12f
  char *buf = NULL;
Packit aea12f
  size_t alloc = BUFSIZ;
Packit aea12f
Packit aea12f
  /* For a regular file, allocate a buffer that has exactly the right
Packit aea12f
     size.  This avoids the need to do dynamic reallocations later.  */
Packit aea12f
  {
Packit aea12f
    struct stat st;
Packit aea12f
Packit aea12f
    if (fstat (fileno (stream), &st) >= 0 && S_ISREG (st.st_mode))
Packit aea12f
      {
Packit aea12f
        off_t pos = ftello (stream);
Packit aea12f
Packit aea12f
        if (pos >= 0 && pos < st.st_size)
Packit aea12f
          {
Packit aea12f
            off_t alloc_off = st.st_size - pos;
Packit aea12f
Packit aea12f
            /* '1' below, accounts for the trailing NUL.  */
Packit Service 991b93
            if (PTRDIFF_MAX - 1 < alloc_off)
Packit aea12f
              {
Packit aea12f
                errno = ENOMEM;
Packit aea12f
                return NULL;
Packit aea12f
              }
Packit aea12f
Packit aea12f
            alloc = alloc_off + 1;
Packit aea12f
          }
Packit aea12f
      }
Packit aea12f
  }
Packit aea12f
Packit aea12f
  if (!(buf = malloc (alloc)))
Packit aea12f
    return NULL; /* errno is ENOMEM.  */
Packit aea12f
Packit aea12f
  {
Packit aea12f
    size_t size = 0; /* number of bytes read so far */
Packit aea12f
    int save_errno;
Packit aea12f
Packit aea12f
    for (;;)
Packit aea12f
      {
Packit aea12f
        /* This reads 1 more than the size of a regular file
Packit aea12f
           so that we get eof immediately.  */
Packit aea12f
        size_t requested = alloc - size;
Packit aea12f
        size_t count = fread (buf + size, 1, requested, stream);
Packit aea12f
        size += count;
Packit aea12f
Packit aea12f
        if (count != requested)
Packit aea12f
          {
Packit aea12f
            save_errno = errno;
Packit aea12f
            if (ferror (stream))
Packit aea12f
              break;
Packit aea12f
Packit aea12f
            /* Shrink the allocated memory if possible.  */
Packit aea12f
            if (size < alloc - 1)
Packit aea12f
              {
Packit Service 991b93
                if (flags & RF_SENSITIVE)
Packit Service 991b93
                  {
Packit Service 991b93
                    char *smaller_buf = malloc (size + 1);
Packit Service 991b93
                    if (smaller_buf == NULL)
Packit Service 991b93
                      explicit_bzero (buf + size, alloc - size);
Packit Service 991b93
                    else
Packit Service 991b93
                      {
Packit Service 991b93
                        memcpy (smaller_buf, buf, size);
Packit Service 991b93
                        explicit_bzero (buf, alloc);
Packit Service 991b93
                        free (buf);
Packit Service 991b93
                        buf = smaller_buf;
Packit Service 991b93
                      }
Packit Service 991b93
                  }
Packit Service 991b93
                else
Packit Service 991b93
                  {
Packit Service 991b93
                    char *smaller_buf = realloc (buf, size + 1);
Packit Service 991b93
                    if (smaller_buf != NULL)
Packit Service 991b93
                      buf = smaller_buf;
Packit Service 991b93
                  }
Packit aea12f
              }
Packit aea12f
Packit aea12f
            buf[size] = '\0';
Packit aea12f
            *length = size;
Packit aea12f
            return buf;
Packit aea12f
          }
Packit aea12f
Packit aea12f
        {
Packit aea12f
          char *new_buf;
Packit Service 991b93
          size_t save_alloc = alloc;
Packit aea12f
Packit Service 991b93
          if (alloc == PTRDIFF_MAX)
Packit aea12f
            {
Packit aea12f
              save_errno = ENOMEM;
Packit aea12f
              break;
Packit aea12f
            }
Packit aea12f
Packit Service 991b93
          if (alloc < PTRDIFF_MAX - alloc / 2)
Packit aea12f
            alloc = alloc + alloc / 2;
Packit aea12f
          else
Packit Service 991b93
            alloc = PTRDIFF_MAX;
Packit aea12f
Packit Service 991b93
          if (flags & RF_SENSITIVE)
Packit Service 991b93
            {
Packit Service 991b93
              new_buf = malloc (alloc);
Packit Service 991b93
              if (!new_buf)
Packit Service 991b93
                {
Packit Service 991b93
                  /* BUF should be cleared below after the loop.  */
Packit Service 991b93
                  save_errno = errno;
Packit Service 991b93
                  break;
Packit Service 991b93
                }
Packit Service 991b93
              memcpy (new_buf, buf, save_alloc);
Packit Service 991b93
              explicit_bzero (buf, save_alloc);
Packit Service 991b93
              free (buf);
Packit Service 991b93
              buf = new_buf;
Packit Service 991b93
            }
Packit Service 991b93
          else if (!(new_buf = realloc (buf, alloc)))
Packit aea12f
            {
Packit aea12f
              save_errno = errno;
Packit aea12f
              break;
Packit aea12f
            }
Packit aea12f
Packit aea12f
          buf = new_buf;
Packit aea12f
        }
Packit aea12f
      }
Packit aea12f
Packit Service 991b93
    if (flags & RF_SENSITIVE)
Packit Service 991b93
      explicit_bzero (buf, alloc);
Packit Service 991b93
Packit aea12f
    free (buf);
Packit aea12f
    errno = save_errno;
Packit aea12f
    return NULL;
Packit aea12f
  }
Packit aea12f
}
Packit aea12f
Packit Service 991b93
/* Open and read the contents of FILENAME, and return a newly
Packit Service 991b93
   allocated string with the content, and set *LENGTH to the length of
Packit Service 991b93
   the string.  The string is zero-terminated, but the terminating
Packit Service 991b93
   zero byte is not counted in *LENGTH.  On errors, *LENGTH is
Packit Service 991b93
   undefined, errno preserves the values set by system functions (if
Packit Service 991b93
   any), and NULL is returned.
Packit Service 991b93
Packit Service 991b93
   If the RF_BINARY flag is set in FLAGS, the file is opened in binary
Packit Service 991b93
   mode.  If the RF_SENSITIVE flag is set in FLAGS, the memory buffer
Packit Service 991b93
   internally allocated will be cleared upon failure.  */
Packit Service 991b93
char *
Packit Service 991b93
read_file (const char *filename, int flags, size_t *length)
Packit aea12f
{
Packit Service 991b93
  const char *mode = (flags & RF_BINARY) ? "rbe" : "re";
Packit aea12f
  FILE *stream = fopen (filename, mode);
Packit aea12f
  char *out;
Packit aea12f
  int save_errno;
Packit aea12f
Packit aea12f
  if (!stream)
Packit aea12f
    return NULL;
Packit aea12f
Packit Service 991b93
  if (flags & RF_SENSITIVE)
Packit Service 991b93
    setvbuf (stream, NULL, _IONBF, 0);
Packit Service 991b93
Packit Service 991b93
  out = fread_file (stream, flags, length);
Packit aea12f
Packit aea12f
  save_errno = errno;
Packit aea12f
Packit aea12f
  if (fclose (stream) != 0)
Packit aea12f
    {
Packit aea12f
      if (out)
Packit aea12f
        {
Packit aea12f
          save_errno = errno;
Packit Service 991b93
          if (flags & RF_SENSITIVE)
Packit Service 991b93
            explicit_bzero (out, *length);
Packit aea12f
          free (out);
Packit aea12f
        }
Packit aea12f
      errno = save_errno;
Packit aea12f
      return NULL;
Packit aea12f
    }
Packit aea12f
Packit aea12f
  return out;
Packit aea12f
}