/src/gnutls/gl/read-file.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* read-file.c -- read file contents into a string |
2 | | Copyright (C) 2006, 2009-2025 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 memcpy, memset_explicit. */ |
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 | 0 | { |
54 | 0 | char *buf = NULL; |
55 | 0 | 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 | 0 | { |
60 | 0 | struct stat st; |
61 | |
|
62 | 0 | if (fstat (fileno (stream), &st) >= 0 && S_ISREG (st.st_mode)) |
63 | 0 | { |
64 | 0 | off_t pos = ftello (stream); |
65 | |
|
66 | 0 | if (pos >= 0 && pos < st.st_size) |
67 | 0 | { |
68 | 0 | off_t alloc_off = st.st_size - pos; |
69 | | |
70 | | /* '1' below, accounts for the trailing NUL. */ |
71 | 0 | if (PTRDIFF_MAX - 1 < alloc_off) |
72 | 0 | { |
73 | 0 | errno = ENOMEM; |
74 | 0 | return NULL; |
75 | 0 | } |
76 | | |
77 | 0 | alloc = alloc_off + 1; |
78 | 0 | } |
79 | 0 | } |
80 | 0 | } |
81 | | |
82 | 0 | if (!(buf = malloc (alloc))) |
83 | 0 | return NULL; /* errno is ENOMEM. */ |
84 | | |
85 | 0 | { |
86 | 0 | size_t size = 0; /* number of bytes read so far */ |
87 | 0 | int saved_errno; |
88 | |
|
89 | 0 | for (;;) |
90 | 0 | { |
91 | | /* This reads 1 more than the size of a regular file |
92 | | so that we get eof immediately. */ |
93 | 0 | size_t requested = alloc - size; |
94 | 0 | size_t count = fread (buf + size, 1, requested, stream); |
95 | 0 | size += count; |
96 | |
|
97 | 0 | if (count != requested) |
98 | 0 | { |
99 | 0 | saved_errno = errno; |
100 | 0 | if (ferror (stream)) |
101 | 0 | break; |
102 | | |
103 | | /* Shrink the allocated memory if possible. */ |
104 | 0 | if (size < alloc - 1) |
105 | 0 | { |
106 | 0 | if (flags & RF_SENSITIVE) |
107 | 0 | { |
108 | 0 | char *smaller_buf = malloc (size + 1); |
109 | 0 | if (smaller_buf == NULL) |
110 | 0 | memset_explicit (buf + size, 0, alloc - size); |
111 | 0 | else |
112 | 0 | { |
113 | 0 | memcpy (smaller_buf, buf, size); |
114 | 0 | memset_explicit (buf, 0, alloc); |
115 | 0 | free (buf); |
116 | 0 | buf = smaller_buf; |
117 | 0 | } |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | char *smaller_buf = realloc (buf, size + 1); |
122 | 0 | if (smaller_buf != NULL) |
123 | 0 | buf = smaller_buf; |
124 | 0 | } |
125 | 0 | } |
126 | |
|
127 | 0 | buf[size] = '\0'; |
128 | 0 | *length = size; |
129 | 0 | return buf; |
130 | 0 | } |
131 | | |
132 | 0 | { |
133 | 0 | char *new_buf; |
134 | 0 | size_t saved_alloc = alloc; |
135 | |
|
136 | 0 | if (alloc == PTRDIFF_MAX) |
137 | 0 | { |
138 | 0 | saved_errno = ENOMEM; |
139 | 0 | break; |
140 | 0 | } |
141 | | |
142 | 0 | if (alloc < PTRDIFF_MAX - alloc / 2) |
143 | 0 | alloc = alloc + alloc / 2; |
144 | 0 | else |
145 | 0 | alloc = PTRDIFF_MAX; |
146 | |
|
147 | 0 | if (flags & RF_SENSITIVE) |
148 | 0 | { |
149 | 0 | new_buf = malloc (alloc); |
150 | 0 | if (!new_buf) |
151 | 0 | { |
152 | | /* BUF should be cleared below after the loop. */ |
153 | 0 | saved_errno = errno; |
154 | 0 | break; |
155 | 0 | } |
156 | 0 | memcpy (new_buf, buf, saved_alloc); |
157 | 0 | memset_explicit (buf, 0, saved_alloc); |
158 | 0 | free (buf); |
159 | 0 | } |
160 | 0 | else if (!(new_buf = realloc (buf, alloc))) |
161 | 0 | { |
162 | 0 | saved_errno = errno; |
163 | 0 | break; |
164 | 0 | } |
165 | | |
166 | 0 | buf = new_buf; |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | 0 | if (flags & RF_SENSITIVE) |
171 | 0 | memset_explicit (buf, 0, alloc); |
172 | |
|
173 | 0 | free (buf); |
174 | 0 | errno = saved_errno; |
175 | 0 | return NULL; |
176 | 0 | } |
177 | 0 | } |
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 | 0 | { |
192 | 0 | const char *mode = (flags & RF_BINARY) ? "rbe" : "re"; |
193 | 0 | FILE *stream = fopen (filename, mode); |
194 | 0 | char *out; |
195 | |
|
196 | 0 | if (!stream) |
197 | 0 | return NULL; |
198 | | |
199 | 0 | if (flags & RF_SENSITIVE) |
200 | 0 | setvbuf (stream, NULL, _IONBF, 0); |
201 | |
|
202 | 0 | out = fread_file (stream, flags, length); |
203 | |
|
204 | 0 | if (fclose (stream) != 0) |
205 | 0 | { |
206 | 0 | if (out) |
207 | 0 | { |
208 | 0 | if (flags & RF_SENSITIVE) |
209 | 0 | memset_explicit (out, 0, *length); |
210 | 0 | free (out); |
211 | 0 | } |
212 | 0 | return NULL; |
213 | 0 | } |
214 | | |
215 | 0 | return out; |
216 | 0 | } |