1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 /* 41 * Copyright 2020 Robert Mustacchi 42 */ 43 44 #include "lint.h" 45 #include "file64.h" 46 #include <sys/types.h> 47 #include <stdio.h> 48 #include <mtlib.h> 49 #include <fcntl.h> 50 #include <unistd.h> 51 #include <limits.h> 52 #include <thread.h> 53 #include <synch.h> 54 #include <stdlib.h> 55 #include <errno.h> 56 #include "stdiom.h" 57 #include "xpg6.h" 58 59 /* Final argument to _endopen depends on build environment */ 60 #define LARGE_OPEN (_FILE_OFFSET_BITS == 64) 61 62 FILE * 63 fopen(const char *name, const char *type) /* open name, return new stream */ 64 { 65 FILE *iop; 66 FILE *rc; 67 68 iop = _findiop(); 69 /* 70 * Note that iop is not locked here, since no other thread could 71 * possibly call _endopen with the same iop at this point. 72 */ 73 rc = _endopen(name, type, iop, LARGE_OPEN); 74 75 if (rc == NULL && iop != NULL) 76 iop->_flag = 0; /* release iop */ 77 78 return (rc); 79 } 80 81 static FILE * 82 _freopen_null(const char *type, FILE *iop) 83 { 84 char plus, mode; 85 int oflag, nflag, fd, accmode; 86 mbstate_t *mb; 87 88 if (iop == NULL || iop->_flag == 0) { 89 errno = EBADF; 90 return (NULL); 91 } 92 93 /* 94 * If this is not a file-based stream (as in we have no file 95 * descriptor), then we need to close this, but still actually return an 96 * error. 97 */ 98 if (_get_fd(iop) == -1) { 99 (void) close_fd(iop); 100 errno = EBADF; 101 return (NULL); 102 } 103 104 if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 105 (void) _fflush_u(iop); 106 107 if (iop->_flag & _IOMYBUF) { 108 free((char *)iop->_base - PUSHBACK); 109 } 110 iop->_base = NULL; 111 iop->_ptr = NULL; 112 /* 113 * Clear stream orientation, clear stream encoding rule, and set 114 * stream's mbstate_t object to describe an initial conversion state. 115 */ 116 mb = _getmbstate(iop); 117 if (mb != NULL) 118 (void) memset(mb, 0, sizeof (mbstate_t)); 119 iop->_cnt = 0; 120 _setorientation(iop, _NO_MODE); 121 122 fd = FILENO(iop); 123 mode = type[0]; 124 if (mode != 'r' && mode != 'w' && mode != 'a') { 125 errno = EINVAL; 126 goto errret; 127 } 128 129 if ((oflag = fcntl(fd, F_GETFL)) == -1) 130 goto errret; 131 132 if ((plus = type[1]) == 'b') 133 plus = type[2]; 134 135 /* 136 * Because the filename has not been specified, the underlying file 137 * will not be closed and reopened. The access modes of an open 138 * file descriptor can't be changed via fcntl(). When '+' is 139 * specified, the old access mode needs to be O_RDWR. When 'r' is 140 * specified, the old access mode needs to be O_RDONLY or O_RDWR. 141 * When 'a' or 'w' is specified, the old access mode needs to be 142 * O_WRONLY or O_RDWR. Otherwise, fail with EBADF, indicating that 143 * the underlying file descriptor was not opened with a mode that 144 * would allow the stream to do successful I/O with the requested mode. 145 */ 146 147 accmode = oflag & O_ACCMODE; 148 if ((accmode == O_RDONLY && (mode != 'r' || plus == '+')) || 149 (accmode == O_WRONLY && (mode == 'r' || plus == '+'))) { 150 (void) close(fd); 151 errno = EBADF; 152 goto errret_noclose; 153 } 154 155 #ifdef _LP64 156 iop->_flag &= ~_DEF_FLAG_MASK; /* clear lower 8-bits */ 157 if (mode == 'r') { 158 iop->_flag |= _IOREAD; 159 nflag = oflag & ~O_APPEND; 160 } else if (mode == 'w') { 161 iop->_flag |= _IOWRT; 162 nflag = oflag & ~O_APPEND; 163 } else { 164 iop->_flag |= _IOWRT; 165 nflag = oflag | O_APPEND; 166 } 167 if (plus == '+') { 168 iop->_flag = (iop->_flag & ~(_IOREAD | _IOWRT)) | _IORW; 169 } 170 #else 171 if (mode == 'r') { 172 iop->_flag = _IOREAD; 173 nflag = oflag & ~O_APPEND; 174 } else if (mode == 'w') { 175 iop->_flag = _IOWRT; 176 nflag = oflag & ~O_APPEND; 177 } else { 178 iop->_flag = _IOWRT; 179 nflag = oflag | O_APPEND; 180 } 181 if (plus == '+') { 182 iop->_flag = _IORW; 183 } 184 #endif 185 /* 186 * Change mode of underlying fd as much as possible without closing 187 * and reopening it. Ignore truncate failures, eg. with stdout. 188 */ 189 if (mode == 'w') 190 (void) ftruncate64(fd, (off64_t)0); 191 192 if (fcntl(fd, F_SETFL, nflag) == -1) 193 goto errret; 194 195 /* ignore seek failures, eg. with pipes */ 196 (void) lseek64(fd, (off64_t)0, SEEK_SET); 197 198 return (iop); 199 200 errret: 201 if (errno != EBADF) 202 (void) close(fd); 203 204 errret_noclose: 205 iop->_flag = 0; /* release iop */ 206 return (NULL); 207 } 208 209 FILE * 210 freopen(const char *name, const char *type, FILE *iop) 211 { 212 FILE *rc; 213 rmutex_t *lk; 214 215 if (name == NULL && __xpg6 & _C99SUSv3_freopen_NULL_filename) { 216 /* 217 * XPG6: If name is a null pointer, freopen will attempt to 218 * change the mode of the stream to that specified by type. 219 */ 220 FLOCKFILE(lk, iop); 221 rc = _freopen_null(type, iop); 222 FUNLOCKFILE(lk); 223 return (rc); 224 } 225 /* 226 * there may be concurrent calls to reopen the same stream - need 227 * to make freopen() atomic 228 */ 229 FLOCKFILE(lk, iop); 230 /* 231 * new function to do everything that fclose() does, except 232 * to release the iop - this cannot yet be released since 233 * _endopen() is yet to be called on this iop 234 */ 235 236 (void) close_fd(iop); 237 238 rc = _endopen(name, type, iop, LARGE_OPEN); 239 240 if (rc == NULL) 241 iop->_flag = 0; /* release iop */ 242 243 FUNLOCKFILE(lk); 244 return (rc); 245 } 246