blob: 1ea3ef57481445662ae3d323f06ca12db786c27a [file] [log] [blame]
Dmitriy Ivanov623b0d02014-05-14 23:11:05 -07001/* $OpenBSD: findfp.c,v 1.15 2013/12/17 16:33:27 deraadt Exp $ */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002/*-
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Chris Torek.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <stdio.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080035
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080036#include <errno.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080037#include <fcntl.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038#include <stdlib.h>
39#include <string.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080040#include <sys/param.h>
41#include <unistd.h>
42
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080043#include "local.h"
44#include "glue.h"
Elliott Hughes6a03abc2014-11-03 12:32:17 -080045#include "private/thread_private.h"
46
47#define ALIGNBYTES (sizeof(uintptr_t) - 1)
48#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
Calin Juravlec20de902014-03-20 15:21:32 +000049
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080050#define NDYNAMIC 10 /* add ten more whenever necessary */
51
52#define std(flags, file) \
Chih-Hung Hsiehdc6599e2014-11-04 12:09:35 -080053 {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \
54 {(unsigned char *)(__sFext+file), 0},NULL,0,{0},{0},{0,0},0,0}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055
Kenny Rootf5823402011-02-12 07:13:44 -080056_THREAD_PRIVATE_MUTEX(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080057
Elliott Hughes29ee6392015-12-07 11:07:15 -080058// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
59#define SBUF_INIT {0,0}
60#if defined(__LP64__)
61#define MBSTATE_T_INIT {{0},{0}}
62#else
63#define MBSTATE_T_INIT {{0}}
64#endif
65#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
66
Elliott Hughesbb46afd2015-12-04 18:03:12 -080067static struct __sfileext __sFext[3] = {
Elliott Hughes29ee6392015-12-07 11:07:15 -080068 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
69 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
70 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080071};
Elliott Hughesf0141df2015-10-12 12:44:23 -070072
73// __sF is exported for backwards compatibility. Until M, we didn't have symbols
74// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080075FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080076 std(__SRD, STDIN_FILENO),
77 std(__SWR, STDOUT_FILENO),
78 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080079};
Elliott Hughesf0141df2015-10-12 12:44:23 -070080
Elliott Hughes168667c2014-11-14 14:42:59 -080081FILE* stdin = &__sF[0];
82FILE* stdout = &__sF[1];
83FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080084
Elliott Hughesbb46afd2015-12-04 18:03:12 -080085struct glue __sglue = { NULL, 3, __sF };
86static struct glue* lastglue = &__sglue;
87
Elliott Hughes021335e2016-01-19 16:28:15 -080088static glue* moreglue(int n) {
89 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080090
Elliott Hughes021335e2016-01-19 16:28:15 -080091 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
92 if (data == nullptr) return nullptr;
93
94 glue* g = reinterpret_cast<glue*>(data);
95 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
96 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
97 g->next = NULL;
98 g->niobs = n;
99 g->iobs = p;
100 while (--n >= 0) {
101 *p = empty;
102 _FILEEXT_SETUP(p, pext);
103 p++;
104 pext++;
105 }
106 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800107}
108
109/*
110 * Find a free FILE for fopen et al.
111 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800112FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800113 FILE *fp;
114 int n;
115 struct glue *g;
116
Kenny Rootf5823402011-02-12 07:13:44 -0800117 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
118 for (g = &__sglue; g != NULL; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800119 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
120 if (fp->_flags == 0)
121 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800122 }
Kenny Rootf5823402011-02-12 07:13:44 -0800123
124 /* release lock while mallocing */
125 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
126 if ((g = moreglue(NDYNAMIC)) == NULL)
127 return (NULL);
128 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
129 lastglue->next = g;
130 lastglue = g;
131 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800132found:
133 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800134 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800135 fp->_p = NULL; /* no current pointer */
136 fp->_w = 0; /* nothing to read or write */
137 fp->_r = 0;
138 fp->_bf._base = NULL; /* no buffer */
139 fp->_bf._size = 0;
140 fp->_lbfsize = 0; /* not line buffered */
141 fp->_file = -1; /* no file */
142/* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */
143 fp->_lb._base = NULL; /* no line buffer */
144 fp->_lb._size = 0;
145 _FILEEXT_INIT(fp);
146 return (fp);
147}
148
Elliott Hughes021335e2016-01-19 16:28:15 -0800149extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150 /* (void) _fwalk(fclose); */
151 (void) _fwalk(__sflush); /* `cheating' */
152}
Elliott Hughes923f1652016-01-19 15:46:05 -0800153
154int fclose(FILE* fp) {
155 if (fp->_flags == 0) {
156 // Already freed!
157 errno = EBADF;
158 return EOF;
159 }
160
161 FLOCKFILE(fp);
162 WCIO_FREE(fp);
163 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
164 if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
165 r = EOF;
166 }
167 if (fp->_flags & __SMBF) free(fp->_bf._base);
168 if (HASUB(fp)) FREEUB(fp);
169 if (HASLB(fp)) FREELB(fp);
170
171 // Poison this FILE so accesses after fclose will be obvious.
172 fp->_file = -1;
173 fp->_r = fp->_w = 0;
174
175 // Release this FILE for reuse.
176 fp->_flags = 0;
177 FUNLOCKFILE(fp);
178 return (r);
179}
180
181int fileno(FILE* fp) {
182 FLOCKFILE(fp);
183 int result = fileno_unlocked(fp);
184 FUNLOCKFILE(fp);
185 return result;
186}
Elliott Hughes021335e2016-01-19 16:28:15 -0800187
188// Small standard I/O/seek/close functions.
189// These maintain the `known seek offset' for seek optimisation.
190int __sread(void* cookie, char* buf, int n) {
191 FILE* fp = reinterpret_cast<FILE*>(cookie);
192 int ret = TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
193 // If the read succeeded, update the current offset.
194 if (ret >= 0) {
195 fp->_offset += ret;
196 } else {
197 fp->_flags &= ~__SOFF; // Paranoia.
198 }
199 return ret;
200}
201
202int __swrite(void* cookie, const char* buf, int n) {
203 FILE* fp = reinterpret_cast<FILE*>(cookie);
204 if (fp->_flags & __SAPP) {
205 (void) TEMP_FAILURE_RETRY(lseek(fp->_file, 0, SEEK_END));
206 }
207 fp->_flags &= ~__SOFF; // In case FAPPEND mode is set.
208 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
209}
210
211// TODO: _FILE_OFFSET_BITS=64.
212fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
213 FILE* fp = reinterpret_cast<FILE*>(cookie);
214 off_t ret = TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
215 if (ret == -1) {
216 fp->_flags &= ~__SOFF;
217 } else {
218 fp->_flags |= __SOFF;
219 fp->_offset = ret;
220 }
221 return ret;
222}
223
224int __sclose(void* cookie) {
225 FILE* fp = reinterpret_cast<FILE*>(cookie);
226 return close(fp->_file);
227}