blob: 4d6438b239c806c003ded66e96b6aa83d1ae5d3c [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
Elliott Hughes53cf3482016-08-09 13:06:41 -070034#define __BIONIC_NO_STDIO_FORTIFY
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080035#include <stdio.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080036
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080037#include <errno.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080038#include <fcntl.h>
Elliott Hughes2704bd12016-01-20 17:14:53 -080039#include <limits.h>
Elliott Hughes20788ae2016-06-09 15:16:32 -070040#include <paths.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080041#include <stdlib.h>
42#include <string.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080043#include <sys/param.h>
Elliott Hughes023c3072016-01-22 15:04:51 -080044#include <sys/stat.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080045#include <unistd.h>
46
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047#include "local.h"
48#include "glue.h"
Elliott Hughesfb3873d2016-08-10 11:07:54 -070049#include "private/bionic_fortify.h"
Elliott Hughes023c3072016-01-22 15:04:51 -080050#include "private/ErrnoRestorer.h"
Elliott Hughes6a03abc2014-11-03 12:32:17 -080051#include "private/thread_private.h"
52
53#define ALIGNBYTES (sizeof(uintptr_t) - 1)
54#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
Calin Juravlec20de902014-03-20 15:21:32 +000055
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080056#define NDYNAMIC 10 /* add ten more whenever necessary */
57
Elliott Hughes70715da2016-08-01 16:35:17 -070058#define PRINTF_IMPL(expr) \
59 va_list ap; \
60 va_start(ap, fmt); \
61 int result = (expr); \
62 va_end(ap); \
63 return result;
64
Elliott Hughes023c3072016-01-22 15:04:51 -080065#define std(flags, file) \
66 {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,nullptr,__swrite, \
67 {(unsigned char *)(__sFext+file), 0},nullptr,0,{0},{0},{0,0},0,0}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080068
Kenny Rootf5823402011-02-12 07:13:44 -080069_THREAD_PRIVATE_MUTEX(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080070
Elliott Hughes33a8cb12017-07-25 18:06:46 -070071#define SBUF_INIT {}
72#define WCHAR_IO_DATA_INIT {}
Elliott Hughes29ee6392015-12-07 11:07:15 -080073
Elliott Hughesbb46afd2015-12-04 18:03:12 -080074static struct __sfileext __sFext[3] = {
Elliott Hughes023c3072016-01-22 15:04:51 -080075 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
76 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
77 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080078};
Elliott Hughesf0141df2015-10-12 12:44:23 -070079
80// __sF is exported for backwards compatibility. Until M, we didn't have symbols
81// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080082FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080083 std(__SRD, STDIN_FILENO),
84 std(__SWR, STDOUT_FILENO),
85 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080086};
Elliott Hughesf0141df2015-10-12 12:44:23 -070087
Elliott Hughes168667c2014-11-14 14:42:59 -080088FILE* stdin = &__sF[0];
89FILE* stdout = &__sF[1];
90FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091
Elliott Hughesbb46afd2015-12-04 18:03:12 -080092struct glue __sglue = { NULL, 3, __sF };
93static struct glue* lastglue = &__sglue;
94
Elliott Hughes2704bd12016-01-20 17:14:53 -080095class ScopedFileLock {
96 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -070097 explicit ScopedFileLock(FILE* fp) : fp_(fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -080098 FLOCKFILE(fp_);
99 }
100 ~ScopedFileLock() {
101 FUNLOCKFILE(fp_);
102 }
103
104 private:
105 FILE* fp_;
106};
107
Elliott Hughes021335e2016-01-19 16:28:15 -0800108static glue* moreglue(int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800109 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800110
Elliott Hughes2704bd12016-01-20 17:14:53 -0800111 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
112 if (data == nullptr) return nullptr;
Elliott Hughes021335e2016-01-19 16:28:15 -0800113
Elliott Hughes2704bd12016-01-20 17:14:53 -0800114 glue* g = reinterpret_cast<glue*>(data);
115 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
116 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
117 g->next = NULL;
118 g->niobs = n;
119 g->iobs = p;
120 while (--n >= 0) {
121 *p = empty;
122 _FILEEXT_SETUP(p, pext);
123 p++;
124 pext++;
125 }
126 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800127}
128
Elliott Hughes80e4c152017-07-21 13:57:55 -0700129static inline void free_fgetln_buffer(FILE* fp) {
130 if (__predict_false(fp->_lb._base != nullptr)) {
131 free(fp->_lb._base);
132 fp->_lb._base = nullptr;
133 }
134}
135
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800136/*
137 * Find a free FILE for fopen et al.
138 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800139FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800140 FILE *fp;
141 int n;
142 struct glue *g;
143
Kenny Rootf5823402011-02-12 07:13:44 -0800144 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
145 for (g = &__sglue; g != NULL; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800146 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
147 if (fp->_flags == 0)
148 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800149 }
Kenny Rootf5823402011-02-12 07:13:44 -0800150
151 /* release lock while mallocing */
152 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
153 if ((g = moreglue(NDYNAMIC)) == NULL)
154 return (NULL);
155 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
156 lastglue->next = g;
157 lastglue = g;
158 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800159found:
160 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800161 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800162 fp->_p = NULL; /* no current pointer */
163 fp->_w = 0; /* nothing to read or write */
164 fp->_r = 0;
165 fp->_bf._base = NULL; /* no buffer */
166 fp->_bf._size = 0;
167 fp->_lbfsize = 0; /* not line buffered */
168 fp->_file = -1; /* no file */
Elliott Hughes023c3072016-01-22 15:04:51 -0800169
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800170 fp->_lb._base = NULL; /* no line buffer */
171 fp->_lb._size = 0;
172 _FILEEXT_INIT(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800173
174 // Caller sets cookie, _read/_write etc.
175 // We explicitly clear _seek and _seek64 to prevent subtle bugs.
176 fp->_seek = nullptr;
177 _EXT(fp)->_seek64 = nullptr;
178
179 return fp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800180}
181
Elliott Hughes021335e2016-01-19 16:28:15 -0800182extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800183 // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
184 _fwalk(__sflush);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800185}
Elliott Hughes923f1652016-01-19 15:46:05 -0800186
Elliott Hughes023c3072016-01-22 15:04:51 -0800187static FILE* __fopen(int fd, int flags) {
188#if !defined(__LP64__)
189 if (fd > SHRT_MAX) {
190 errno = EMFILE;
191 return nullptr;
192 }
193#endif
194
195 FILE* fp = __sfp();
196 if (fp != nullptr) {
197 fp->_file = fd;
198 fp->_flags = flags;
199 fp->_cookie = fp;
200 fp->_read = __sread;
201 fp->_write = __swrite;
202 fp->_close = __sclose;
203 _EXT(fp)->_seek64 = __sseek64;
204 }
205 return fp;
206}
207
208FILE* fopen(const char* file, const char* mode) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700209 int mode_flags;
210 int flags = __sflags(mode, &mode_flags);
Elliott Hughes023c3072016-01-22 15:04:51 -0800211 if (flags == 0) return nullptr;
212
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700213 int fd = open(file, mode_flags, DEFFILEMODE);
Elliott Hughes023c3072016-01-22 15:04:51 -0800214 if (fd == -1) {
215 return nullptr;
216 }
217
218 FILE* fp = __fopen(fd, flags);
219 if (fp == nullptr) {
220 ErrnoRestorer errno_restorer;
221 close(fd);
222 return nullptr;
223 }
224
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700225 // For append mode, even though we use O_APPEND, we need to seek to the end now.
226 if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
Elliott Hughes023c3072016-01-22 15:04:51 -0800227 return fp;
228}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800229__strong_alias(fopen64, fopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800230
231FILE* fdopen(int fd, const char* mode) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700232 int mode_flags;
233 int flags = __sflags(mode, &mode_flags);
Elliott Hughes023c3072016-01-22 15:04:51 -0800234 if (flags == 0) return nullptr;
235
236 // Make sure the mode the user wants is a subset of the actual mode.
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700237 int fd_flags = fcntl(fd, F_GETFL, 0);
238 if (fd_flags == -1) return nullptr;
239 int tmp = fd_flags & O_ACCMODE;
240 if (tmp != O_RDWR && (tmp != (mode_flags & O_ACCMODE))) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800241 errno = EINVAL;
242 return nullptr;
243 }
244
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700245 // Make sure O_APPEND is set on the underlying fd if our mode has 'a'.
246 // POSIX says we just take the current offset of the underlying fd.
247 if ((mode_flags & O_APPEND) && !(fd_flags & O_APPEND)) {
248 if (fcntl(fd, F_SETFL, fd_flags | O_APPEND) == -1) return nullptr;
249 }
Elliott Hughes023c3072016-01-22 15:04:51 -0800250
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700251 // Make sure O_CLOEXEC is set on the underlying fd if our mode has 'x'.
252 if ((mode_flags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800253 fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
254 }
255
256 return __fopen(fd, flags);
257}
258
259// Re-direct an existing, open (probably) file to some other file.
260// ANSI is written such that the original file gets closed if at
261// all possible, no matter what.
262// TODO: rewrite this mess completely.
263FILE* freopen(const char* file, const char* mode, FILE* fp) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700264 int mode_flags;
265 int flags = __sflags(mode, &mode_flags);
Elliott Hughes023c3072016-01-22 15:04:51 -0800266 if (flags == 0) {
267 fclose(fp);
268 return nullptr;
269 }
270
271 ScopedFileLock sfl(fp);
272
273 // There are actually programs that depend on being able to "freopen"
274 // descriptors that weren't originally open. Keep this from breaking.
275 // Remember whether the stream was open to begin with, and which file
276 // descriptor (if any) was associated with it. If it was attached to
277 // a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
278 // should work. This is unnecessary if it was not a Unix file.
279 int isopen, wantfd;
280 if (fp->_flags == 0) {
281 fp->_flags = __SEOF; // Hold on to it.
282 isopen = 0;
283 wantfd = -1;
284 } else {
285 // Flush the stream; ANSI doesn't require this.
286 if (fp->_flags & __SWR) __sflush(fp);
287
288 // If close is NULL, closing is a no-op, hence pointless.
289 isopen = fp->_close != NULL;
290 if ((wantfd = fp->_file) < 0 && isopen) {
291 (*fp->_close)(fp->_cookie);
292 isopen = 0;
293 }
294 }
295
296 // Get a new descriptor to refer to the new file.
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700297 int fd = open(file, mode_flags, DEFFILEMODE);
Elliott Hughes023c3072016-01-22 15:04:51 -0800298 if (fd < 0 && isopen) {
299 // If out of fd's close the old one and try again.
300 if (errno == ENFILE || errno == EMFILE) {
301 (*fp->_close)(fp->_cookie);
302 isopen = 0;
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700303 fd = open(file, mode_flags, DEFFILEMODE);
Elliott Hughes023c3072016-01-22 15:04:51 -0800304 }
305 }
306
307 int sverrno = errno;
308
309 // Finish closing fp. Even if the open succeeded above, we cannot
310 // keep fp->_base: it may be the wrong size. This loses the effect
311 // of any setbuffer calls, but stdio has always done this before.
312 if (isopen && fd != wantfd) (*fp->_close)(fp->_cookie);
313 if (fp->_flags & __SMBF) free(fp->_bf._base);
314 fp->_w = 0;
315 fp->_r = 0;
316 fp->_p = NULL;
317 fp->_bf._base = NULL;
318 fp->_bf._size = 0;
319 fp->_lbfsize = 0;
320 if (HASUB(fp)) FREEUB(fp);
321 _UB(fp)._size = 0;
322 WCIO_FREE(fp);
Elliott Hughes80e4c152017-07-21 13:57:55 -0700323 free_fgetln_buffer(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800324 fp->_lb._size = 0;
325
326 if (fd < 0) { // Did not get it after all.
327 fp->_flags = 0; // Release.
328 errno = sverrno; // Restore errno in case _close clobbered it.
329 return nullptr;
330 }
331
332 // If reopening something that was open before on a real file, try
333 // to maintain the descriptor. Various C library routines (perror)
334 // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
335 if (wantfd >= 0 && fd != wantfd) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700336 if (dup3(fd, wantfd, mode_flags & O_CLOEXEC) >= 0) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800337 close(fd);
338 fd = wantfd;
339 }
340 }
341
342 // _file is only a short.
343 if (fd > SHRT_MAX) {
344 fp->_flags = 0; // Release.
345 errno = EMFILE;
346 return nullptr;
347 }
348
349 fp->_flags = flags;
350 fp->_file = fd;
351 fp->_cookie = fp;
352 fp->_read = __sread;
353 fp->_write = __swrite;
354 fp->_close = __sclose;
355 _EXT(fp)->_seek64 = __sseek64;
356
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700357 // For append mode, even though we use O_APPEND, we need to seek to the end now.
358 if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
Elliott Hughes023c3072016-01-22 15:04:51 -0800359 return fp;
360}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800361__strong_alias(freopen64, freopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800362
Elliott Hughes923f1652016-01-19 15:46:05 -0800363int fclose(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800364 if (fp->_flags == 0) {
365 // Already freed!
366 errno = EBADF;
367 return EOF;
368 }
Elliott Hughes923f1652016-01-19 15:46:05 -0800369
Elliott Hughes2704bd12016-01-20 17:14:53 -0800370 ScopedFileLock sfl(fp);
371 WCIO_FREE(fp);
372 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
373 if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
374 r = EOF;
375 }
376 if (fp->_flags & __SMBF) free(fp->_bf._base);
377 if (HASUB(fp)) FREEUB(fp);
Elliott Hughes80e4c152017-07-21 13:57:55 -0700378 free_fgetln_buffer(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800379
Elliott Hughes2704bd12016-01-20 17:14:53 -0800380 // Poison this FILE so accesses after fclose will be obvious.
381 fp->_file = -1;
382 fp->_r = fp->_w = 0;
Elliott Hughes923f1652016-01-19 15:46:05 -0800383
Elliott Hughes2704bd12016-01-20 17:14:53 -0800384 // Release this FILE for reuse.
385 fp->_flags = 0;
386 return r;
Elliott Hughes923f1652016-01-19 15:46:05 -0800387}
388
Elliott Hughescceaf062016-07-29 16:31:52 -0700389int fileno_unlocked(FILE* fp) {
390 int fd = fp->_file;
391 if (fd == -1) {
392 errno = EBADF;
393 return -1;
394 }
395 return fd;
396}
397
Elliott Hughes923f1652016-01-19 15:46:05 -0800398int fileno(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800399 ScopedFileLock sfl(fp);
400 return fileno_unlocked(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800401}
Elliott Hughes021335e2016-01-19 16:28:15 -0800402
Elliott Hughescceaf062016-07-29 16:31:52 -0700403void clearerr_unlocked(FILE* fp) {
404 return __sclearerr(fp);
405}
406
407void clearerr(FILE* fp) {
408 ScopedFileLock sfl(fp);
409 clearerr_unlocked(fp);
410}
411
412int feof_unlocked(FILE* fp) {
Elliott Hughes70715da2016-08-01 16:35:17 -0700413 return ((fp->_flags & __SEOF) != 0);
Elliott Hughescceaf062016-07-29 16:31:52 -0700414}
415
416int feof(FILE* fp) {
417 ScopedFileLock sfl(fp);
418 return feof_unlocked(fp);
419}
420
421int ferror_unlocked(FILE* fp) {
422 return __sferror(fp);
423}
424
425int ferror(FILE* fp) {
426 ScopedFileLock sfl(fp);
427 return ferror_unlocked(fp);
428}
429
Elliott Hughes021335e2016-01-19 16:28:15 -0800430int __sread(void* cookie, char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800431 FILE* fp = reinterpret_cast<FILE*>(cookie);
432 return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800433}
434
435int __swrite(void* cookie, const char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800436 FILE* fp = reinterpret_cast<FILE*>(cookie);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800437 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800438}
439
Elliott Hughes021335e2016-01-19 16:28:15 -0800440fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800441 FILE* fp = reinterpret_cast<FILE*>(cookie);
442 return TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
Elliott Hughes021335e2016-01-19 16:28:15 -0800443}
444
Elliott Hughes023c3072016-01-22 15:04:51 -0800445off64_t __sseek64(void* cookie, off64_t offset, int whence) {
446 FILE* fp = reinterpret_cast<FILE*>(cookie);
447 return TEMP_FAILURE_RETRY(lseek64(fp->_file, offset, whence));
448}
449
Elliott Hughes021335e2016-01-19 16:28:15 -0800450int __sclose(void* cookie) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800451 FILE* fp = reinterpret_cast<FILE*>(cookie);
452 return close(fp->_file);
453}
454
Elliott Hughes023c3072016-01-22 15:04:51 -0800455static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
456 // Use `_seek64` if set, but fall back to `_seek`.
457 if (_EXT(fp)->_seek64 != nullptr) {
458 return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence);
459 } else if (fp->_seek != nullptr) {
Elliott Hughes955426e2016-01-26 18:25:52 -0800460 off64_t result = (*fp->_seek)(fp->_cookie, offset, whence);
461#if !defined(__LP64__)
462 // Avoid sign extension if off64_t is larger than off_t.
463 if (result != -1) result &= 0xffffffff;
464#endif
465 return result;
Elliott Hughes023c3072016-01-22 15:04:51 -0800466 } else {
467 errno = ESPIPE;
468 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800469 }
Elliott Hughes2704bd12016-01-20 17:14:53 -0800470}
471
Elliott Hughes9677fab2016-01-25 15:50:59 -0800472static off64_t __ftello64_unlocked(FILE* fp) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800473 // Find offset of underlying I/O object, then adjust for buffered bytes.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800474 __sflush(fp); // May adjust seek offset on append stream.
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700475
Elliott Hughes9677fab2016-01-25 15:50:59 -0800476 off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800477 if (result == -1) {
478 return -1;
479 }
480
481 if (fp->_flags & __SRD) {
482 // Reading. Any unread characters (including
483 // those from ungetc) cause the position to be
484 // smaller than that in the underlying object.
485 result -= fp->_r;
486 if (HASUB(fp)) result -= fp->_ur;
487 } else if (fp->_flags & __SWR && fp->_p != NULL) {
488 // Writing. Any buffered characters cause the
489 // position to be greater than that in the
490 // underlying object.
491 result += fp->_p - fp->_bf._base;
492 }
493 return result;
494}
495
Elliott Hughes9677fab2016-01-25 15:50:59 -0800496int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800497 ScopedFileLock sfl(fp);
498
Elliott Hughes023c3072016-01-22 15:04:51 -0800499 // Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800500 // After this, whence is either SEEK_SET or SEEK_END.
501 if (whence == SEEK_CUR) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800502 fpos64_t current_offset = __ftello64_unlocked(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800503 if (current_offset == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800504 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800505 }
506 offset += current_offset;
507 whence = SEEK_SET;
508 } else if (whence != SEEK_SET && whence != SEEK_END) {
509 errno = EINVAL;
Elliott Hughes9677fab2016-01-25 15:50:59 -0800510 return -1;
511 }
512
513 // If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
514 if (off_t_bits == 32 && offset > LONG_MAX) {
515 errno = EOVERFLOW;
516 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800517 }
518
519 if (fp->_bf._base == NULL) __smakebuf(fp);
520
521 // Flush unwritten data and attempt the seek.
Elliott Hughes023c3072016-01-22 15:04:51 -0800522 if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800523 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800524 }
525
526 // Success: clear EOF indicator and discard ungetc() data.
527 if (HASUB(fp)) FREEUB(fp);
528 fp->_p = fp->_bf._base;
529 fp->_r = 0;
530 /* fp->_w = 0; */ /* unnecessary (I think...) */
531 fp->_flags &= ~__SEOF;
532 return 0;
533}
534
Elliott Hughes9677fab2016-01-25 15:50:59 -0800535int fseeko(FILE* fp, off_t offset, int whence) {
536 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
537 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
538}
539__strong_alias(fseek, fseeko);
540
541int fseeko64(FILE* fp, off64_t offset, int whence) {
542 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
Elliott Hughes2704bd12016-01-20 17:14:53 -0800543}
544
Elliott Hughes9677fab2016-01-25 15:50:59 -0800545int fsetpos(FILE* fp, const fpos_t* pos) {
546 return fseeko(fp, *pos, SEEK_SET);
547}
548
549int fsetpos64(FILE* fp, const fpos64_t* pos) {
550 return fseeko64(fp, *pos, SEEK_SET);
551}
552
Elliott Hughes2704bd12016-01-20 17:14:53 -0800553off_t ftello(FILE* fp) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800554 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
555 off64_t result = ftello64(fp);
556 if (result > LONG_MAX) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800557 errno = EOVERFLOW;
558 return -1;
559 }
Elliott Hughes9677fab2016-01-25 15:50:59 -0800560 return result;
561}
562__strong_alias(ftell, ftello);
563
564off64_t ftello64(FILE* fp) {
565 ScopedFileLock sfl(fp);
566 return __ftello64_unlocked(fp);
Elliott Hughes021335e2016-01-19 16:28:15 -0800567}
Elliott Hughes023c3072016-01-22 15:04:51 -0800568
Elliott Hughes023c3072016-01-22 15:04:51 -0800569int fgetpos(FILE* fp, fpos_t* pos) {
570 *pos = ftello(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800571 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800572}
573
Elliott Hughes9677fab2016-01-25 15:50:59 -0800574int fgetpos64(FILE* fp, fpos64_t* pos) {
575 *pos = ftello64(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800576 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800577}
Elliott Hughes03e65eb2016-01-26 14:13:04 -0800578
579static FILE* __funopen(const void* cookie,
580 int (*read_fn)(void*, char*, int),
581 int (*write_fn)(void*, const char*, int),
582 int (*close_fn)(void*)) {
583 if (read_fn == nullptr && write_fn == nullptr) {
584 errno = EINVAL;
585 return nullptr;
586 }
587
588 FILE* fp = __sfp();
589 if (fp == nullptr) return nullptr;
590
591 if (read_fn != nullptr && write_fn != nullptr) {
592 fp->_flags = __SRW;
593 } else if (read_fn != nullptr) {
594 fp->_flags = __SRD;
595 } else if (write_fn != nullptr) {
596 fp->_flags = __SWR;
597 }
598
599 fp->_file = -1;
600 fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
601 fp->_read = read_fn;
602 fp->_write = write_fn;
603 fp->_close = close_fn;
604
605 return fp;
606}
607
608FILE* funopen(const void* cookie,
609 int (*read_fn)(void*, char*, int),
610 int (*write_fn)(void*, const char*, int),
611 fpos_t (*seek_fn)(void*, fpos_t, int),
612 int (*close_fn)(void*)) {
613 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
614 if (fp != nullptr) {
615 fp->_seek = seek_fn;
616 }
617 return fp;
618}
619
620FILE* funopen64(const void* cookie,
621 int (*read_fn)(void*, char*, int),
622 int (*write_fn)(void*, const char*, int),
623 fpos64_t (*seek_fn)(void*, fpos64_t, int),
624 int (*close_fn)(void*)) {
625 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
626 if (fp != nullptr) {
627 _EXT(fp)->_seek64 = seek_fn;
628 }
629 return fp;
630}
Elliott Hughes20788ae2016-06-09 15:16:32 -0700631
Elliott Hughes53cf3482016-08-09 13:06:41 -0700632int asprintf(char** s, const char* fmt, ...) {
633 PRINTF_IMPL(vasprintf(s, fmt, ap));
634}
635
Elliott Hughes20788ae2016-06-09 15:16:32 -0700636char* ctermid(char* s) {
637 return s ? strcpy(s, _PATH_TTY) : const_cast<char*>(_PATH_TTY);
638}
Elliott Hughescceaf062016-07-29 16:31:52 -0700639
Elliott Hughes70715da2016-08-01 16:35:17 -0700640int dprintf(int fd, const char* fmt, ...) {
641 PRINTF_IMPL(vdprintf(fd, fmt, ap));
642}
643
644int fprintf(FILE* fp, const char* fmt, ...) {
645 PRINTF_IMPL(vfprintf(fp, fmt, ap));
646}
647
Elliott Hughescceaf062016-07-29 16:31:52 -0700648int fgetc(FILE* fp) {
649 return getc(fp);
650}
651
652int fputc(int c, FILE* fp) {
653 return putc(c, fp);
654}
655
Elliott Hughes70715da2016-08-01 16:35:17 -0700656int fscanf(FILE* fp, const char* fmt, ...) {
657 PRINTF_IMPL(vfscanf(fp, fmt, ap));
658}
659
660int fwprintf(FILE* fp, const wchar_t* fmt, ...) {
661 PRINTF_IMPL(vfwprintf(fp, fmt, ap));
662}
663
664int fwscanf(FILE* fp, const wchar_t* fmt, ...) {
665 PRINTF_IMPL(vfwscanf(fp, fmt, ap));
666}
667
668int getc(FILE* fp) {
669 ScopedFileLock sfl(fp);
670 return getc_unlocked(fp);
671}
672
673int getc_unlocked(FILE* fp) {
674 return __sgetc(fp);
675}
676
677int getchar_unlocked() {
678 return getc_unlocked(stdin);
679}
680
681int getchar() {
682 return getc(stdin);
683}
684
Elliott Hughescceaf062016-07-29 16:31:52 -0700685ssize_t getline(char** buf, size_t* len, FILE* fp) {
686 return getdelim(buf, len, '\n', fp);
687}
688
689wint_t getwc(FILE* fp) {
690 return fgetwc(fp);
691}
692
693wint_t getwchar() {
694 return fgetwc(stdin);
695}
696
Elliott Hughes70715da2016-08-01 16:35:17 -0700697int printf(const char* fmt, ...) {
698 PRINTF_IMPL(vfprintf(stdout, fmt, ap));
699}
700
701int putc(int c, FILE* fp) {
702 ScopedFileLock sfl(fp);
703 return putc_unlocked(c, fp);
704}
705
706int putc_unlocked(int c, FILE* fp) {
707 if (cantwrite(fp)) {
708 errno = EBADF;
709 return EOF;
710 }
711 _SET_ORIENTATION(fp, -1);
712 if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && c != '\n')) {
713 return (*fp->_p++ = c);
714 }
715 return (__swbuf(c, fp));
716}
717
718int putchar(int c) {
719 return putc(c, stdout);
720}
721
722int putchar_unlocked(int c) {
723 return putc_unlocked(c, stdout);
724}
725
Elliott Hughescceaf062016-07-29 16:31:52 -0700726wint_t putwc(wchar_t wc, FILE* fp) {
727 return fputwc(wc, fp);
728}
729
730wint_t putwchar(wchar_t wc) {
731 return fputwc(wc, stdout);
732}
733
Elliott Hughesd1f25a72016-08-05 15:53:03 -0700734int remove(const char* path) {
735 if (unlink(path) != -1) return 0;
736 if (errno != EISDIR) return -1;
737 return rmdir(path);
738}
739
Elliott Hughescceaf062016-07-29 16:31:52 -0700740void rewind(FILE* fp) {
741 ScopedFileLock sfl(fp);
742 fseek(fp, 0, SEEK_SET);
743 clearerr_unlocked(fp);
744}
745
Elliott Hughes70715da2016-08-01 16:35:17 -0700746int scanf(const char* fmt, ...) {
747 PRINTF_IMPL(vfscanf(stdin, fmt, ap));
748}
749
Elliott Hughescceaf062016-07-29 16:31:52 -0700750void setbuf(FILE* fp, char* buf) {
751 setbuffer(fp, buf, BUFSIZ);
752}
753
754void setbuffer(FILE* fp, char* buf, int size) {
755 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
756}
757
758int setlinebuf(FILE* fp) {
759 return setvbuf(fp, nullptr, _IOLBF, 0);
760}
761
Elliott Hughes53cf3482016-08-09 13:06:41 -0700762int snprintf(char* s, size_t n, const char* fmt, ...) {
763 PRINTF_IMPL(vsnprintf(s, n, fmt, ap));
764}
765
766int sprintf(char* s, const char* fmt, ...) {
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700767 PRINTF_IMPL(vsprintf(s, fmt, ap));
Elliott Hughes53cf3482016-08-09 13:06:41 -0700768}
769
770int sscanf(const char* s, const char* fmt, ...) {
771 PRINTF_IMPL(vsscanf(s, fmt, ap));
772}
773
Elliott Hughes70715da2016-08-01 16:35:17 -0700774int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) {
775 PRINTF_IMPL(vswprintf(s, n, fmt, ap));
776}
777
778int swscanf(const wchar_t* s, const wchar_t* fmt, ...) {
779 PRINTF_IMPL(vswscanf(s, fmt, ap));
780}
781
Elliott Hughescceaf062016-07-29 16:31:52 -0700782int vprintf(const char* fmt, va_list ap) {
783 return vfprintf(stdout, fmt, ap);
784}
785
786int vscanf(const char* fmt, va_list ap) {
787 return vfscanf(stdin, fmt, ap);
788}
789
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700790int vsnprintf(char* s, size_t n, const char* fmt, va_list ap) {
791 // stdio internals use int rather than size_t.
792 static_assert(INT_MAX <= SSIZE_MAX, "SSIZE_MAX too large to fit in int");
793
794 __check_count("vsnprintf", "size", n);
795
796 // Stdio internals do not deal correctly with zero length buffer.
797 char dummy;
798 if (n == 0) {
799 s = &dummy;
800 n = 1;
801 }
802
803 FILE f;
804 __sfileext fext;
805 _FILEEXT_SETUP(&f, &fext);
806 f._file = -1;
807 f._flags = __SWR | __SSTR;
808 f._bf._base = f._p = reinterpret_cast<unsigned char*>(s);
809 f._bf._size = f._w = n - 1;
810
811 int result = __vfprintf(&f, fmt, ap);
812 *f._p = '\0';
813 return result;
814}
815
Elliott Hughes53cf3482016-08-09 13:06:41 -0700816int vsprintf(char* s, const char* fmt, va_list ap) {
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700817 return vsnprintf(s, SSIZE_MAX, fmt, ap);
Elliott Hughes53cf3482016-08-09 13:06:41 -0700818}
819
Elliott Hughescceaf062016-07-29 16:31:52 -0700820int vwprintf(const wchar_t* fmt, va_list ap) {
821 return vfwprintf(stdout, fmt, ap);
822}
823
824int vwscanf(const wchar_t* fmt, va_list ap) {
825 return vfwscanf(stdin, fmt, ap);
826}
Elliott Hughes70715da2016-08-01 16:35:17 -0700827
828int wprintf(const wchar_t* fmt, ...) {
829 PRINTF_IMPL(vfwprintf(stdout, fmt, ap));
830}
831
832int wscanf(const wchar_t* fmt, ...) {
833 PRINTF_IMPL(vfwscanf(stdin, fmt, ap));
834}
Dan Albert3037ea42016-10-06 15:46:45 -0700835
836namespace {
837
838namespace phony {
839#include <bits/struct_file.h>
840}
841
842static_assert(sizeof(::__sFILE) == sizeof(phony::__sFILE),
843 "size mismatch between `struct __sFILE` implementation and public stub");
844static_assert(alignof(::__sFILE) == alignof(phony::__sFILE),
845 "alignment mismatch between `struct __sFILE` implementation and public stub");
846
847}