1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009 David Schultz <das@FreeBSD.org> 5 * Copyright (c) 2021 Dell EMC 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 #include "namespace.h" 32 #include <sys/param.h> 33 #include <errno.h> 34 #include <limits.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include "un-namespace.h" 39 40 #include "libc_private.h" 41 #include "local.h" 42 43 static inline size_t 44 p2roundup(size_t n) 45 { 46 47 if (!powerof2(n)) { 48 n--; 49 n |= n >> 1; 50 n |= n >> 2; 51 n |= n >> 4; 52 n |= n >> 8; 53 n |= n >> 16; 54 #if SIZE_T_MAX > 0xffffffffU 55 n |= n >> 32; 56 #endif 57 n++; 58 } 59 return (n); 60 } 61 62 /* 63 * Expand *linep to hold len bytes (up to SSIZE_MAX + 1). 64 */ 65 static inline int 66 expandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp) 67 { 68 char *newline; 69 size_t newcap; 70 71 if (len > (size_t)SSIZE_MAX + 1) { 72 errno = EOVERFLOW; 73 return (-1); 74 } 75 if (len > *capp) { 76 if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */ 77 newcap = (size_t)SSIZE_MAX + 1; 78 else 79 newcap = p2roundup(len); 80 newline = realloc(*linep, newcap); 81 if (newline == NULL) 82 return (-1); 83 *capp = newcap; 84 *linep = newline; 85 } 86 return (0); 87 } 88 89 /* 90 * Append the src buffer to the *dstp buffer. The buffers are of 91 * length srclen and *dstlenp, respectively, and dst has space for 92 * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated 93 * appropriately, and *dstp is reallocated if needed. Returns 0 on 94 * success, -1 on allocation failure. 95 */ 96 static int 97 sappend(char ** __restrict dstp, size_t * __restrict dstlenp, 98 size_t * __restrict dstcapp, char * __restrict src, size_t srclen) 99 { 100 101 /* ensure room for srclen + dstlen + terminating NUL */ 102 if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp)) 103 return (-1); 104 memcpy(*dstp + *dstlenp, src, srclen); 105 *dstlenp += srclen; 106 return (0); 107 } 108 109 ssize_t 110 getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, 111 FILE * __restrict fp) 112 { 113 u_char *endp; 114 size_t linelen; 115 116 FLOCKFILE_CANCELSAFE(fp); 117 ORIENT(fp, -1); 118 119 if (linep == NULL || linecapp == NULL) { 120 errno = EINVAL; 121 goto error; 122 } 123 124 if (*linep == NULL) 125 *linecapp = 0; 126 127 if (fp->_r <= 0 && __srefill(fp)) { 128 /* If fp is at EOF already, we just need space for the NUL. */ 129 if (!__sfeof(fp) || expandtofit(linep, 1, linecapp)) 130 goto error; 131 (*linep)[0] = '\0'; 132 linelen = -1; 133 goto end; 134 } 135 136 linelen = 0; 137 while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) { 138 if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r)) 139 goto error; 140 errno = 0; 141 if (__srefill(fp)) { 142 if (__sfeof(fp)) 143 goto done; 144 if (errno == EAGAIN) { 145 /* 146 * We need to undo a partial read that has 147 * been placed into linep or we would otherwise 148 * lose it on the next read. 149 */ 150 while (linelen > 0) { 151 if (__ungetc((*linep)[--linelen], 152 fp) == EOF) 153 goto error; 154 } 155 /* 156 * This is not strictly needed but it is 157 * possible a consumer has worked around an 158 * older EAGAIN bug by buffering a partial 159 * return. 160 */ 161 (*linep)[0] = '\0'; 162 } 163 goto error; 164 } 165 } 166 endp++; /* snarf the delimiter, too */ 167 if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p)) 168 goto error; 169 fp->_r -= endp - fp->_p; 170 fp->_p = endp; 171 done: 172 /* Invariant: *linep has space for at least linelen+1 bytes. */ 173 (*linep)[linelen] = '\0'; 174 end: 175 FUNLOCKFILE_CANCELSAFE(); 176 return (linelen); 177 178 error: 179 fp->_flags |= __SERR; 180 linelen = -1; 181 goto end; 182 } 183