Coverage Report

Created: 2025-03-18 06:55

/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
}