1 /* read-file.c -- read file contents into a string
2    Copyright (C) 2006, 2009-2020 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 *
fread_file(FILE * stream,int flags,size_t * length)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               buf = new_buf;
160             }
161           else if (!(new_buf = realloc (buf, alloc)))
162             {
163               save_errno = errno;
164               break;
165             }
166 
167           buf = new_buf;
168         }
169       }
170 
171     if (flags & RF_SENSITIVE)
172       explicit_bzero (buf, alloc);
173 
174     free (buf);
175     errno = save_errno;
176     return NULL;
177   }
178 }
179 
180 /* Open and read the contents of FILENAME, and return a newly
181    allocated string with the content, and set *LENGTH to the length of
182    the string.  The string is zero-terminated, but the terminating
183    zero byte is not counted in *LENGTH.  On errors, *LENGTH is
184    undefined, errno preserves the values set by system functions (if
185    any), and NULL is returned.
186 
187    If the RF_BINARY flag is set in FLAGS, the file is opened in binary
188    mode.  If the RF_SENSITIVE flag is set in FLAGS, the memory buffer
189    internally allocated will be cleared upon failure.  */
190 char *
read_file(const char * filename,int flags,size_t * length)191 read_file (const char *filename, int flags, size_t *length)
192 {
193   const char *mode = (flags & RF_BINARY) ? "rbe" : "re";
194   FILE *stream = fopen (filename, mode);
195   char *out;
196   int save_errno;
197 
198   if (!stream)
199     return NULL;
200 
201   if (flags & RF_SENSITIVE)
202     setvbuf (stream, NULL, _IONBF, 0);
203 
204   out = fread_file (stream, flags, length);
205 
206   save_errno = errno;
207 
208   if (fclose (stream) != 0)
209     {
210       if (out)
211         {
212           save_errno = errno;
213           if (flags & RF_SENSITIVE)
214             explicit_bzero (out, *length);
215           free (out);
216         }
217       errno = save_errno;
218       return NULL;
219     }
220 
221   return out;
222 }
223