| Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/gl/lib/randread.c |
| Source code | Switch to Preprocessed file |
| Line | Source | Count | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | /* Generate buffers of random data. | - | ||||||||||||
| 2 | - | |||||||||||||
| 3 | Copyright (C) 2006-2018 Free Software Foundation, Inc. | - | ||||||||||||
| 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 of the License, or | - | ||||||||||||
| 8 | (at your option) 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 | /* Written by Paul Eggert. */ | - | ||||||||||||
| 19 | - | |||||||||||||
| 20 | /* FIXME: Improve performance by adding support for the RDRAND machine | - | ||||||||||||
| 21 | instruction if available (e.g., Ivy Bridge processors). */ | - | ||||||||||||
| 22 | - | |||||||||||||
| 23 | #include <config.h> | - | ||||||||||||
| 24 | - | |||||||||||||
| 25 | #include "randread.h" | - | ||||||||||||
| 26 | - | |||||||||||||
| 27 | #include <errno.h> | - | ||||||||||||
| 28 | #include <error.h> | - | ||||||||||||
| 29 | #include <exitfail.h> | - | ||||||||||||
| 30 | #include <fcntl.h> | - | ||||||||||||
| 31 | #include <quote.h> | - | ||||||||||||
| 32 | #include <stdalign.h> | - | ||||||||||||
| 33 | #include <stdbool.h> | - | ||||||||||||
| 34 | #include <stdint.h> | - | ||||||||||||
| 35 | #include <stdio.h> | - | ||||||||||||
| 36 | #include <stdlib.h> | - | ||||||||||||
| 37 | #include <string.h> | - | ||||||||||||
| 38 | #include <sys/time.h> | - | ||||||||||||
| 39 | #include <unistd.h> | - | ||||||||||||
| 40 | - | |||||||||||||
| 41 | #include "gettext.h" | - | ||||||||||||
| 42 | #define _(msgid) gettext (msgid) | - | ||||||||||||
| 43 | - | |||||||||||||
| 44 | #include "rand-isaac.h" | - | ||||||||||||
| 45 | #include "stdio-safer.h" | - | ||||||||||||
| 46 | #include "unlocked-io.h" | - | ||||||||||||
| 47 | #include "xalloc.h" | - | ||||||||||||
| 48 | - | |||||||||||||
| 49 | #ifndef __attribute__ | - | ||||||||||||
| 50 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) | - | ||||||||||||
| 51 | # define __attribute__(x) /* empty */ | - | ||||||||||||
| 52 | # endif | - | ||||||||||||
| 53 | #endif | - | ||||||||||||
| 54 | - | |||||||||||||
| 55 | #ifndef ATTRIBUTE_NORETURN | - | ||||||||||||
| 56 | # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) | - | ||||||||||||
| 57 | #endif | - | ||||||||||||
| 58 | - | |||||||||||||
| 59 | #ifndef MIN | - | ||||||||||||
| 60 | # define MIN(a, b) ((a) < (b) ? (a) : (b)) | - | ||||||||||||
| 61 | #endif | - | ||||||||||||
| 62 | - | |||||||||||||
| 63 | #if _STRING_ARCH_unaligned || _STRING_INLINE_unaligned | - | ||||||||||||
| 64 | # define ALIGNED_POINTER(ptr, type) true | - | ||||||||||||
| 65 | #else | - | ||||||||||||
| 66 | # define ALIGNED_POINTER(ptr, type) ((size_t) (ptr) % alignof (type) == 0) | - | ||||||||||||
| 67 | #endif | - | ||||||||||||
| 68 | - | |||||||||||||
| 69 | #ifndef NAME_OF_NONCE_DEVICE | - | ||||||||||||
| 70 | # define NAME_OF_NONCE_DEVICE "/dev/urandom" | - | ||||||||||||
| 71 | #endif | - | ||||||||||||
| 72 | - | |||||||||||||
| 73 | /* The maximum buffer size used for reads of random data. Using the | - | ||||||||||||
| 74 | value 2 * ISAAC_BYTES makes this the largest power of two that | - | ||||||||||||
| 75 | would not otherwise cause struct randread_source to grow. */ | - | ||||||||||||
| 76 | #define RANDREAD_BUFFER_SIZE (2 * ISAAC_BYTES) | - | ||||||||||||
| 77 | - | |||||||||||||
| 78 | /* A source of random data for generating random buffers. */ | - | ||||||||||||
| 79 | struct randread_source | - | ||||||||||||
| 80 | { | - | ||||||||||||
| 81 | /* Stream to read random bytes from. If null, the current | - | ||||||||||||
| 82 | implementation uses an internal PRNG (ISAAC). */ | - | ||||||||||||
| 83 | FILE *source; | - | ||||||||||||
| 84 | - | |||||||||||||
| 85 | /* Function to call, and its argument, if there is an input error or | - | ||||||||||||
| 86 | end of file when reading from the stream; errno is nonzero if | - | ||||||||||||
| 87 | there was an error. If this function returns, it should fix the | - | ||||||||||||
| 88 | problem before returning. The default handler assumes that | - | ||||||||||||
| 89 | handler_arg is the file name of the source. */ | - | ||||||||||||
| 90 | void (*handler) (void const *); | - | ||||||||||||
| 91 | void const *handler_arg; | - | ||||||||||||
| 92 | - | |||||||||||||
| 93 | /* The buffer for SOURCE. It's kept here to simplify storage | - | ||||||||||||
| 94 | allocation and to make it easier to clear out buffered random | - | ||||||||||||
| 95 | data. */ | - | ||||||||||||
| 96 | union | - | ||||||||||||
| 97 | { | - | ||||||||||||
| 98 | /* The stream buffer, if SOURCE is not null. */ | - | ||||||||||||
| 99 | char c[RANDREAD_BUFFER_SIZE]; | - | ||||||||||||
| 100 | - | |||||||||||||
| 101 | /* The buffered ISAAC pseudorandom buffer, if SOURCE is null. */ | - | ||||||||||||
| 102 | struct isaac | - | ||||||||||||
| 103 | { | - | ||||||||||||
| 104 | /* The number of bytes that are buffered at the end of data.b. */ | - | ||||||||||||
| 105 | size_t buffered; | - | ||||||||||||
| 106 | - | |||||||||||||
| 107 | /* State of the ISAAC generator. */ | - | ||||||||||||
| 108 | struct isaac_state state; | - | ||||||||||||
| 109 | - | |||||||||||||
| 110 | /* Up to a buffer's worth of pseudorandom data. */ | - | ||||||||||||
| 111 | union | - | ||||||||||||
| 112 | { | - | ||||||||||||
| 113 | isaac_word w[ISAAC_WORDS]; | - | ||||||||||||
| 114 | unsigned char b[ISAAC_BYTES]; | - | ||||||||||||
| 115 | } data; | - | ||||||||||||
| 116 | } isaac; | - | ||||||||||||
| 117 | } buf; | - | ||||||||||||
| 118 | }; | - | ||||||||||||
| 119 | - | |||||||||||||
| 120 | - | |||||||||||||
| 121 | /* The default error handler. */ | - | ||||||||||||
| 122 | - | |||||||||||||
| 123 | static void ATTRIBUTE_NORETURN | - | ||||||||||||
| 124 | randread_error (void const *file_name) | - | ||||||||||||
| 125 | { | - | ||||||||||||
| 126 | if (file_name)
| 0 | ||||||||||||
| 127 | error (exit_failure, errno, never executed: error (exit_failure, (*__errno_location ()) , (*__errno_location ()) == 0 ? dcgettext (((void *)0), "%s: end of file" , 5) : dcgettext (((void *)0), "%s: read error" , 5) , quote (file_name)); | 0 | ||||||||||||
| 128 | errno == 0 ? _("%s: end of file") : _("%s: read error"), never executed: error (exit_failure, (*__errno_location ()) , (*__errno_location ()) == 0 ? dcgettext (((void *)0), "%s: end of file" , 5) : dcgettext (((void *)0), "%s: read error" , 5) , quote (file_name)); | 0 | ||||||||||||
| 129 | quote (file_name)); never executed: error (exit_failure, (*__errno_location ()) , (*__errno_location ()) == 0 ? dcgettext (((void *)0), "%s: end of file" , 5) : dcgettext (((void *)0), "%s: read error" , 5) , quote (file_name)); | 0 | ||||||||||||
| 130 | abort (); never executed: abort (); | 0 | ||||||||||||
| 131 | } | - | ||||||||||||
| 132 | - | |||||||||||||
| 133 | /* Simply return a new randread_source object with the default error | - | ||||||||||||
| 134 | handler. */ | - | ||||||||||||
| 135 | - | |||||||||||||
| 136 | static struct randread_source * | - | ||||||||||||
| 137 | simple_new (FILE *source, void const *handler_arg) | - | ||||||||||||
| 138 | { | - | ||||||||||||
| 139 | struct randread_source *s = xmalloc (sizeof *s); | - | ||||||||||||
| 140 | s->source = source; | - | ||||||||||||
| 141 | s->handler = randread_error; | - | ||||||||||||
| 142 | s->handler_arg = handler_arg; | - | ||||||||||||
| 143 | return s; executed 655 times by 7 tests: return s;Executed by:
| 655 | ||||||||||||
| 144 | } | - | ||||||||||||
| 145 | - | |||||||||||||
| 146 | /* Put a nonce value into BUFFER, with size BUFSIZE, but do not get | - | ||||||||||||
| 147 | more than BYTES_BOUND bytes' worth of random information from any | - | ||||||||||||
| 148 | nonce device. */ | - | ||||||||||||
| 149 | - | |||||||||||||
| 150 | static void | - | ||||||||||||
| 151 | get_nonce (void *buffer, size_t bufsize, size_t bytes_bound) | - | ||||||||||||
| 152 | { | - | ||||||||||||
| 153 | char *buf = buffer; | - | ||||||||||||
| 154 | ssize_t seeded = 0; | - | ||||||||||||
| 155 | - | |||||||||||||
| 156 | /* Get some data from FD if available. */ | - | ||||||||||||
| 157 | int fd = open (NAME_OF_NONCE_DEVICE, O_RDONLY | O_BINARY); | - | ||||||||||||
| 158 | if (0 <= fd)
| 0-649 | ||||||||||||
| 159 | { | - | ||||||||||||
| 160 | seeded = read (fd, buf, MIN (bufsize, bytes_bound)); | - | ||||||||||||
| 161 | if (seeded < 0)
| 0-649 | ||||||||||||
| 162 | seeded = 0; never executed: seeded = 0; | 0 | ||||||||||||
| 163 | close (fd); | - | ||||||||||||
| 164 | } executed 649 times by 7 tests: end of blockExecuted by:
| 649 | ||||||||||||
| 165 | - | |||||||||||||
| 166 | /* If there's no nonce device, use a poor approximation | - | ||||||||||||
| 167 | by getting the time of day, etc. */ | - | ||||||||||||
| 168 | #define ISAAC_SEED(type, initialize_v) \ | - | ||||||||||||
| 169 | if (seeded < bufsize) \ | - | ||||||||||||
| 170 | { \ | - | ||||||||||||
| 171 | type v; \ | - | ||||||||||||
| 172 | size_t nbytes = MIN (sizeof v, bufsize - seeded); \ | - | ||||||||||||
| 173 | initialize_v; \ | - | ||||||||||||
| 174 | memcpy (buf + seeded, &v, nbytes); \ | - | ||||||||||||
| 175 | seeded += nbytes; \ | - | ||||||||||||
| 176 | } | - | ||||||||||||
| 177 | ISAAC_SEED (struct timeval, gettimeofday (&v, NULL)); executed 618 times by 6 tests: end of blockExecuted by:
| 0-618 | ||||||||||||
| 178 | ISAAC_SEED (pid_t, v = getpid ()); executed 618 times by 6 tests: end of blockExecuted by:
| 0-618 | ||||||||||||
| 179 | ISAAC_SEED (pid_t, v = getppid ()); executed 618 times by 6 tests: end of blockExecuted by:
| 0-618 | ||||||||||||
| 180 | ISAAC_SEED (uid_t, v = getuid ()); executed 618 times by 6 tests: end of blockExecuted by:
| 0-618 | ||||||||||||
| 181 | ISAAC_SEED (uid_t, v = getgid ()); executed 618 times by 6 tests: end of blockExecuted by:
| 0-618 | ||||||||||||
| 182 | - | |||||||||||||
| 183 | #ifdef lint | - | ||||||||||||
| 184 | /* Normally we like having the extra randomness from uninitialized | - | ||||||||||||
| 185 | parts of BUFFER. However, omit this randomness if we want to | - | ||||||||||||
| 186 | avoid false-positives from memory-checking debugging tools. */ | - | ||||||||||||
| 187 | memset (buf + seeded, 0, bufsize - seeded); | - | ||||||||||||
| 188 | #endif | - | ||||||||||||
| 189 | } executed 649 times by 7 tests: end of blockExecuted by:
| 649 | ||||||||||||
| 190 | - | |||||||||||||
| 191 | - | |||||||||||||
| 192 | /* Create and initialize a random data source from NAME, or use a | - | ||||||||||||
| 193 | reasonable default source if NAME is null. BYTES_BOUND is an upper | - | ||||||||||||
| 194 | bound on the number of bytes that will be needed. If zero, it is a | - | ||||||||||||
| 195 | hard bound; otherwise it is just an estimate. | - | ||||||||||||
| 196 | - | |||||||||||||
| 197 | If NAME is not null, NAME is saved for use as the argument of the | - | ||||||||||||
| 198 | default handler. Unless a non-default handler is used, NAME's | - | ||||||||||||
| 199 | lifetime should be at least that of the returned value. | - | ||||||||||||
| 200 | - | |||||||||||||
| 201 | Return NULL (setting errno) on failure. */ | - | ||||||||||||
| 202 | - | |||||||||||||
| 203 | struct randread_source * | - | ||||||||||||
| 204 | randread_new (char const *name, size_t bytes_bound) | - | ||||||||||||
| 205 | { | - | ||||||||||||
| 206 | if (bytes_bound == 0)
| 4-651 | ||||||||||||
| 207 | return simple_new (NULL, NULL); executed 4 times by 1 test: return simple_new ( ((void *)0) , ((void *)0) );Executed by:
| 4 | ||||||||||||
| 208 | else | - | ||||||||||||
| 209 | { | - | ||||||||||||
| 210 | FILE *source = NULL; | - | ||||||||||||
| 211 | struct randread_source *s; | - | ||||||||||||
| 212 | - | |||||||||||||
| 213 | if (name)
| 2-649 | ||||||||||||
| 214 | if (! (source = fopen_safer (name, "rb")))
| 0-2 | ||||||||||||
| 215 | return NULL; never executed: return ((void *)0) ; | 0 | ||||||||||||
| 216 | - | |||||||||||||
| 217 | s = simple_new (source, name); | - | ||||||||||||
| 218 | - | |||||||||||||
| 219 | if (source)
| 2-649 | ||||||||||||
| 220 | setvbuf (source, s->buf.c, _IOFBF, MIN (sizeof s->buf.c, bytes_bound)); executed 2 times by 2 tests: setvbuf (source, s->buf.c, 0 , ((sizeof s->buf.c) < (bytes_bound) ? (sizeof s->buf.c) : (bytes_bound)));Executed by:
| 2 | ||||||||||||
| 221 | else | - | ||||||||||||
| 222 | { | - | ||||||||||||
| 223 | s->buf.isaac.buffered = 0; | - | ||||||||||||
| 224 | get_nonce (s->buf.isaac.state.m, sizeof s->buf.isaac.state.m, | - | ||||||||||||
| 225 | bytes_bound); | - | ||||||||||||
| 226 | isaac_seed (&s->buf.isaac.state); | - | ||||||||||||
| 227 | } executed 649 times by 7 tests: end of blockExecuted by:
| 649 | ||||||||||||
| 228 | - | |||||||||||||
| 229 | return s; executed 651 times by 7 tests: return s;Executed by:
| 651 | ||||||||||||
| 230 | } | - | ||||||||||||
| 231 | } | - | ||||||||||||
| 232 | - | |||||||||||||
| 233 | - | |||||||||||||
| 234 | /* Set S's handler and its argument. HANDLER (HANDLER_ARG) is called | - | ||||||||||||
| 235 | when there is a read error or end of file from the random data | - | ||||||||||||
| 236 | source; errno is nonzero if there was an error. If HANDLER | - | ||||||||||||
| 237 | returns, it should fix the problem before returning. The default | - | ||||||||||||
| 238 | handler assumes that handler_arg is the file name of the source; it | - | ||||||||||||
| 239 | does not return. */ | - | ||||||||||||
| 240 | - | |||||||||||||
| 241 | void | - | ||||||||||||
| 242 | randread_set_handler (struct randread_source *s, void (*handler) (void const *)) | - | ||||||||||||
| 243 | { | - | ||||||||||||
| 244 | s->handler = handler; | - | ||||||||||||
| 245 | } never executed: end of block | 0 | ||||||||||||
| 246 | - | |||||||||||||
| 247 | void | - | ||||||||||||
| 248 | randread_set_handler_arg (struct randread_source *s, void const *handler_arg) | - | ||||||||||||
| 249 | { | - | ||||||||||||
| 250 | s->handler_arg = handler_arg; | - | ||||||||||||
| 251 | } never executed: end of block | 0 | ||||||||||||
| 252 | - | |||||||||||||
| 253 | - | |||||||||||||
| 254 | /* Place SIZE random bytes into the buffer beginning at P, using | - | ||||||||||||
| 255 | the stream in S. */ | - | ||||||||||||
| 256 | - | |||||||||||||
| 257 | static void | - | ||||||||||||
| 258 | readsource (struct randread_source *s, unsigned char *p, size_t size) | - | ||||||||||||
| 259 | { | - | ||||||||||||
| 260 | while (true) | - | ||||||||||||
| 261 | { | - | ||||||||||||
| 262 | size_t inbytes = fread (p, sizeof *p, size, s->source); | - | ||||||||||||
| 263 | int fread_errno = errno; | - | ||||||||||||
| 264 | p += inbytes; | - | ||||||||||||
| 265 | size -= inbytes; | - | ||||||||||||
| 266 | if (size == 0)
| 0-18 | ||||||||||||
| 267 | break; executed 18 times by 2 tests: break;Executed by:
| 18 | ||||||||||||
| 268 | errno = (ferror (s->source) ? fread_errno : 0); | - | ||||||||||||
| 269 | s->handler (s->handler_arg); | - | ||||||||||||
| 270 | } never executed: end of block | 0 | ||||||||||||
| 271 | } executed 18 times by 2 tests: end of blockExecuted by:
| 18 | ||||||||||||
| 272 | - | |||||||||||||
| 273 | - | |||||||||||||
| 274 | /* Place SIZE pseudorandom bytes into the buffer beginning at P, using | - | ||||||||||||
| 275 | the buffered ISAAC generator in ISAAC. */ | - | ||||||||||||
| 276 | - | |||||||||||||
| 277 | static void | - | ||||||||||||
| 278 | readisaac (struct isaac *isaac, void *p, size_t size) | - | ||||||||||||
| 279 | { | - | ||||||||||||
| 280 | size_t inbytes = isaac->buffered; | - | ||||||||||||
| 281 | - | |||||||||||||
| 282 | while (true) | - | ||||||||||||
| 283 | { | - | ||||||||||||
| 284 | char *char_p = p; | - | ||||||||||||
| 285 | - | |||||||||||||
| 286 | if (size <= inbytes)
| 685-6236 | ||||||||||||
| 287 | { | - | ||||||||||||
| 288 | memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, size); | - | ||||||||||||
| 289 | isaac->buffered = inbytes - size; | - | ||||||||||||
| 290 | return; executed 6236 times by 7 tests: return;Executed by:
| 6236 | ||||||||||||
| 291 | } | - | ||||||||||||
| 292 | - | |||||||||||||
| 293 | memcpy (p, isaac->data.b + ISAAC_BYTES - inbytes, inbytes); | - | ||||||||||||
| 294 | p = char_p + inbytes; | - | ||||||||||||
| 295 | size -= inbytes; | - | ||||||||||||
| 296 | - | |||||||||||||
| 297 | /* If P is aligned, write to *P directly to avoid the overhead | - | ||||||||||||
| 298 | of copying from the buffer. */ | - | ||||||||||||
| 299 | if (ALIGNED_POINTER (p, isaac_word)) | - | ||||||||||||
| 300 | { | - | ||||||||||||
| 301 | isaac_word *wp = p; | - | ||||||||||||
| 302 | while (ISAAC_BYTES <= size)
| 669-1023 | ||||||||||||
| 303 | { | - | ||||||||||||
| 304 | isaac_refill (&isaac->state, wp); | - | ||||||||||||
| 305 | wp += ISAAC_WORDS; | - | ||||||||||||
| 306 | size -= ISAAC_BYTES; | - | ||||||||||||
| 307 | if (size == 0)
| 16-1007 | ||||||||||||
| 308 | { | - | ||||||||||||
| 309 | isaac->buffered = 0; | - | ||||||||||||
| 310 | return; executed 16 times by 1 test: return;Executed by:
| 16 | ||||||||||||
| 311 | } | - | ||||||||||||
| 312 | } executed 1007 times by 1 test: end of blockExecuted by:
| 1007 | ||||||||||||
| 313 | p = wp; | - | ||||||||||||
| 314 | } executed 669 times by 7 tests: end of blockExecuted by:
| 669 | ||||||||||||
| 315 | - | |||||||||||||
| 316 | isaac_refill (&isaac->state, isaac->data.w); | - | ||||||||||||
| 317 | inbytes = ISAAC_BYTES; | - | ||||||||||||
| 318 | } executed 669 times by 7 tests: end of blockExecuted by:
| 669 | ||||||||||||
| 319 | } never executed: end of block | 0 | ||||||||||||
| 320 | - | |||||||||||||
| 321 | - | |||||||||||||
| 322 | /* Consume random data from *S to generate a random buffer BUF of size | - | ||||||||||||
| 323 | SIZE. */ | - | ||||||||||||
| 324 | - | |||||||||||||
| 325 | void | - | ||||||||||||
| 326 | randread (struct randread_source *s, void *buf, size_t size) | - | ||||||||||||
| 327 | { | - | ||||||||||||
| 328 | if (s->source)
| 18-6252 | ||||||||||||
| 329 | readsource (s, buf, size); executed 18 times by 2 tests: readsource (s, buf, size);Executed by:
| 18 | ||||||||||||
| 330 | else | - | ||||||||||||
| 331 | readisaac (&s->buf.isaac, buf, size); executed 6252 times by 7 tests: readisaac (&s->buf.isaac, buf, size);Executed by:
| 6252 | ||||||||||||
| 332 | } | - | ||||||||||||
| 333 | - | |||||||||||||
| 334 | - | |||||||||||||
| 335 | /* Clear *S so that it no longer contains undelivered random data, and | - | ||||||||||||
| 336 | deallocate any system resources associated with *S. Return 0 if | - | ||||||||||||
| 337 | successful, a negative number (setting errno) if not (this is rare, | - | ||||||||||||
| 338 | but can occur in theory if there is an input error). */ | - | ||||||||||||
| 339 | - | |||||||||||||
| 340 | int | - | ||||||||||||
| 341 | randread_free (struct randread_source *s) | - | ||||||||||||
| 342 | { | - | ||||||||||||
| 343 | FILE *source = s->source; | - | ||||||||||||
| 344 | explicit_bzero (s, sizeof *s); | - | ||||||||||||
| 345 | free (s); | - | ||||||||||||
| 346 | return (source ? fclose (source) : 0); executed 635 times by 6 tests: return (source ? rpl_fclose (source) : 0);Executed by:
| 635 | ||||||||||||
| 347 | } | - | ||||||||||||
| Source code | Switch to Preprocessed file |