Bump to m4 1.4.19
[platform/upstream/m4.git] / 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 }