root/maint/gnulib/lib/read-file.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fread_file
  2. read_file

   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 file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 2.1 of the
   8    License, or (at your option) any later version.
   9 
  10    This file 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 Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */