blob: 46d717a7162c7eca7741a4006599b2ee1a529eec [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
Josh Gaod1620602017-10-05 13:48:08 -070047#include <async_safe/log.h>
48
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080049#include "local.h"
50#include "glue.h"
Elliott Hughesfb3873d2016-08-10 11:07:54 -070051#include "private/bionic_fortify.h"
Elliott Hughes023c3072016-01-22 15:04:51 -080052#include "private/ErrnoRestorer.h"
Elliott Hughes6a03abc2014-11-03 12:32:17 -080053#include "private/thread_private.h"
54
55#define ALIGNBYTES (sizeof(uintptr_t) - 1)
56#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
Calin Juravlec20de902014-03-20 15:21:32 +000057
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080058#define NDYNAMIC 10 /* add ten more whenever necessary */
59
Elliott Hughes70715da2016-08-01 16:35:17 -070060#define PRINTF_IMPL(expr) \
61 va_list ap; \
62 va_start(ap, fmt); \
63 int result = (expr); \
64 va_end(ap); \
65 return result;
66
Elliott Hughes023c3072016-01-22 15:04:51 -080067#define std(flags, file) \
68 {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,nullptr,__swrite, \
69 {(unsigned char *)(__sFext+file), 0},nullptr,0,{0},{0},{0,0},0,0}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080070
Kenny Rootf5823402011-02-12 07:13:44 -080071_THREAD_PRIVATE_MUTEX(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072
Elliott Hughes33a8cb12017-07-25 18:06:46 -070073#define SBUF_INIT {}
74#define WCHAR_IO_DATA_INIT {}
Elliott Hughes29ee6392015-12-07 11:07:15 -080075
Elliott Hughesbb46afd2015-12-04 18:03:12 -080076static struct __sfileext __sFext[3] = {
Elliott Hughes023c3072016-01-22 15:04:51 -080077 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
78 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
79 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080080};
Elliott Hughesf0141df2015-10-12 12:44:23 -070081
82// __sF is exported for backwards compatibility. Until M, we didn't have symbols
83// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080084FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080085 std(__SRD, STDIN_FILENO),
86 std(__SWR, STDOUT_FILENO),
87 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088};
Elliott Hughesf0141df2015-10-12 12:44:23 -070089
Elliott Hughes168667c2014-11-14 14:42:59 -080090FILE* stdin = &__sF[0];
91FILE* stdout = &__sF[1];
92FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093
Elliott Hughes37ad9592017-10-30 17:47:12 -070094struct glue __sglue = { nullptr, 3, __sF };
Elliott Hughesbb46afd2015-12-04 18:03:12 -080095static struct glue* lastglue = &__sglue;
96
Elliott Hughes2704bd12016-01-20 17:14:53 -080097class ScopedFileLock {
98 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -070099 explicit ScopedFileLock(FILE* fp) : fp_(fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800100 FLOCKFILE(fp_);
101 }
102 ~ScopedFileLock() {
103 FUNLOCKFILE(fp_);
104 }
105
106 private:
107 FILE* fp_;
108};
109
Elliott Hughes021335e2016-01-19 16:28:15 -0800110static glue* moreglue(int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800111 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800112
Elliott Hughes2704bd12016-01-20 17:14:53 -0800113 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
114 if (data == nullptr) return nullptr;
Elliott Hughes021335e2016-01-19 16:28:15 -0800115
Elliott Hughes2704bd12016-01-20 17:14:53 -0800116 glue* g = reinterpret_cast<glue*>(data);
117 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
118 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
Elliott Hughes37ad9592017-10-30 17:47:12 -0700119 g->next = nullptr;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800120 g->niobs = n;
121 g->iobs = p;
122 while (--n >= 0) {
123 *p = empty;
124 _FILEEXT_SETUP(p, pext);
125 p++;
126 pext++;
127 }
128 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800129}
130
Elliott Hughes80e4c152017-07-21 13:57:55 -0700131static inline void free_fgetln_buffer(FILE* fp) {
132 if (__predict_false(fp->_lb._base != nullptr)) {
133 free(fp->_lb._base);
134 fp->_lb._base = nullptr;
135 }
136}
137
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800138/*
139 * Find a free FILE for fopen et al.
140 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800141FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800142 FILE *fp;
143 int n;
144 struct glue *g;
145
Kenny Rootf5823402011-02-12 07:13:44 -0800146 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
Elliott Hughes37ad9592017-10-30 17:47:12 -0700147 for (g = &__sglue; g != nullptr; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800148 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
149 if (fp->_flags == 0)
150 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800151 }
Kenny Rootf5823402011-02-12 07:13:44 -0800152
153 /* release lock while mallocing */
154 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
Elliott Hughes37ad9592017-10-30 17:47:12 -0700155 if ((g = moreglue(NDYNAMIC)) == nullptr) return nullptr;
Kenny Rootf5823402011-02-12 07:13:44 -0800156 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
157 lastglue->next = g;
158 lastglue = g;
159 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800160found:
161 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800162 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
Elliott Hughes37ad9592017-10-30 17:47:12 -0700163 fp->_p = nullptr; /* no current pointer */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800164 fp->_w = 0; /* nothing to read or write */
165 fp->_r = 0;
Elliott Hughes37ad9592017-10-30 17:47:12 -0700166 fp->_bf._base = nullptr; /* no buffer */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800167 fp->_bf._size = 0;
168 fp->_lbfsize = 0; /* not line buffered */
169 fp->_file = -1; /* no file */
Elliott Hughes023c3072016-01-22 15:04:51 -0800170
Elliott Hughes37ad9592017-10-30 17:47:12 -0700171 fp->_lb._base = nullptr; /* no line buffer */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172 fp->_lb._size = 0;
173 _FILEEXT_INIT(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800174
175 // Caller sets cookie, _read/_write etc.
176 // We explicitly clear _seek and _seek64 to prevent subtle bugs.
177 fp->_seek = nullptr;
178 _EXT(fp)->_seek64 = nullptr;
179
180 return fp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800181}
182
Elliott Hughes021335e2016-01-19 16:28:15 -0800183extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800184 // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
185 _fwalk(__sflush);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186}
Elliott Hughes923f1652016-01-19 15:46:05 -0800187
Elliott Hughes023c3072016-01-22 15:04:51 -0800188static FILE* __fopen(int fd, int flags) {
189#if !defined(__LP64__)
190 if (fd > SHRT_MAX) {
191 errno = EMFILE;
192 return nullptr;
193 }
194#endif
195
196 FILE* fp = __sfp();
197 if (fp != nullptr) {
198 fp->_file = fd;
199 fp->_flags = flags;
200 fp->_cookie = fp;
201 fp->_read = __sread;
202 fp->_write = __swrite;
203 fp->_close = __sclose;
204 _EXT(fp)->_seek64 = __sseek64;
205 }
206 return fp;
207}
208
209FILE* fopen(const char* file, const char* mode) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700210 int mode_flags;
211 int flags = __sflags(mode, &mode_flags);
Elliott Hughes023c3072016-01-22 15:04:51 -0800212 if (flags == 0) return nullptr;
213
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700214 int fd = open(file, mode_flags, DEFFILEMODE);
Elliott Hughes023c3072016-01-22 15:04:51 -0800215 if (fd == -1) {
216 return nullptr;
217 }
218
219 FILE* fp = __fopen(fd, flags);
220 if (fp == nullptr) {
221 ErrnoRestorer errno_restorer;
222 close(fd);
223 return nullptr;
224 }
225
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700226 // For append mode, even though we use O_APPEND, we need to seek to the end now.
227 if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
Elliott Hughes023c3072016-01-22 15:04:51 -0800228 return fp;
229}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800230__strong_alias(fopen64, fopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800231
232FILE* fdopen(int fd, const char* mode) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700233 int mode_flags;
234 int flags = __sflags(mode, &mode_flags);
Elliott Hughes023c3072016-01-22 15:04:51 -0800235 if (flags == 0) return nullptr;
236
237 // Make sure the mode the user wants is a subset of the actual mode.
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700238 int fd_flags = fcntl(fd, F_GETFL, 0);
239 if (fd_flags == -1) return nullptr;
240 int tmp = fd_flags & O_ACCMODE;
241 if (tmp != O_RDWR && (tmp != (mode_flags & O_ACCMODE))) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800242 errno = EINVAL;
243 return nullptr;
244 }
245
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700246 // Make sure O_APPEND is set on the underlying fd if our mode has 'a'.
247 // POSIX says we just take the current offset of the underlying fd.
248 if ((mode_flags & O_APPEND) && !(fd_flags & O_APPEND)) {
249 if (fcntl(fd, F_SETFL, fd_flags | O_APPEND) == -1) return nullptr;
250 }
Elliott Hughes023c3072016-01-22 15:04:51 -0800251
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700252 // Make sure O_CLOEXEC is set on the underlying fd if our mode has 'x'.
253 if ((mode_flags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800254 fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
255 }
256
257 return __fopen(fd, flags);
258}
259
260// Re-direct an existing, open (probably) file to some other file.
261// ANSI is written such that the original file gets closed if at
262// all possible, no matter what.
263// TODO: rewrite this mess completely.
264FILE* freopen(const char* file, const char* mode, FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700265 CHECK_FP(fp);
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700266 int mode_flags;
267 int flags = __sflags(mode, &mode_flags);
Elliott Hughes023c3072016-01-22 15:04:51 -0800268 if (flags == 0) {
269 fclose(fp);
270 return nullptr;
271 }
272
273 ScopedFileLock sfl(fp);
274
275 // There are actually programs that depend on being able to "freopen"
276 // descriptors that weren't originally open. Keep this from breaking.
277 // Remember whether the stream was open to begin with, and which file
278 // descriptor (if any) was associated with it. If it was attached to
279 // a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
280 // should work. This is unnecessary if it was not a Unix file.
281 int isopen, wantfd;
282 if (fp->_flags == 0) {
283 fp->_flags = __SEOF; // Hold on to it.
284 isopen = 0;
285 wantfd = -1;
286 } else {
287 // Flush the stream; ANSI doesn't require this.
288 if (fp->_flags & __SWR) __sflush(fp);
289
Elliott Hughes37ad9592017-10-30 17:47:12 -0700290 // If close is null, closing is a no-op, hence pointless.
291 isopen = (fp->_close != nullptr);
Elliott Hughes023c3072016-01-22 15:04:51 -0800292 if ((wantfd = fp->_file) < 0 && isopen) {
293 (*fp->_close)(fp->_cookie);
294 isopen = 0;
295 }
296 }
297
298 // Get a new descriptor to refer to the new file.
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700299 int fd = open(file, mode_flags, DEFFILEMODE);
Elliott Hughes023c3072016-01-22 15:04:51 -0800300 if (fd < 0 && isopen) {
301 // If out of fd's close the old one and try again.
302 if (errno == ENFILE || errno == EMFILE) {
303 (*fp->_close)(fp->_cookie);
304 isopen = 0;
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700305 fd = open(file, mode_flags, DEFFILEMODE);
Elliott Hughes023c3072016-01-22 15:04:51 -0800306 }
307 }
308
309 int sverrno = errno;
310
311 // Finish closing fp. Even if the open succeeded above, we cannot
312 // keep fp->_base: it may be the wrong size. This loses the effect
313 // of any setbuffer calls, but stdio has always done this before.
314 if (isopen && fd != wantfd) (*fp->_close)(fp->_cookie);
315 if (fp->_flags & __SMBF) free(fp->_bf._base);
316 fp->_w = 0;
317 fp->_r = 0;
Elliott Hughes37ad9592017-10-30 17:47:12 -0700318 fp->_p = nullptr;
319 fp->_bf._base = nullptr;
Elliott Hughes023c3072016-01-22 15:04:51 -0800320 fp->_bf._size = 0;
321 fp->_lbfsize = 0;
322 if (HASUB(fp)) FREEUB(fp);
323 _UB(fp)._size = 0;
324 WCIO_FREE(fp);
Elliott Hughes80e4c152017-07-21 13:57:55 -0700325 free_fgetln_buffer(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800326 fp->_lb._size = 0;
327
328 if (fd < 0) { // Did not get it after all.
329 fp->_flags = 0; // Release.
330 errno = sverrno; // Restore errno in case _close clobbered it.
331 return nullptr;
332 }
333
334 // If reopening something that was open before on a real file, try
335 // to maintain the descriptor. Various C library routines (perror)
336 // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
337 if (wantfd >= 0 && fd != wantfd) {
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700338 if (dup3(fd, wantfd, mode_flags & O_CLOEXEC) >= 0) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800339 close(fd);
340 fd = wantfd;
341 }
342 }
343
344 // _file is only a short.
345 if (fd > SHRT_MAX) {
346 fp->_flags = 0; // Release.
347 errno = EMFILE;
348 return nullptr;
349 }
350
351 fp->_flags = flags;
352 fp->_file = fd;
353 fp->_cookie = fp;
354 fp->_read = __sread;
355 fp->_write = __swrite;
356 fp->_close = __sclose;
357 _EXT(fp)->_seek64 = __sseek64;
358
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700359 // For append mode, even though we use O_APPEND, we need to seek to the end now.
360 if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
Elliott Hughes023c3072016-01-22 15:04:51 -0800361 return fp;
362}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800363__strong_alias(freopen64, freopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800364
Elliott Hughes923f1652016-01-19 15:46:05 -0800365int fclose(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700366 CHECK_FP(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800367 if (fp->_flags == 0) {
368 // Already freed!
369 errno = EBADF;
370 return EOF;
371 }
Elliott Hughes923f1652016-01-19 15:46:05 -0800372
Elliott Hughes2704bd12016-01-20 17:14:53 -0800373 ScopedFileLock sfl(fp);
374 WCIO_FREE(fp);
375 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
Elliott Hughes37ad9592017-10-30 17:47:12 -0700376 if (fp->_close != nullptr && (*fp->_close)(fp->_cookie) < 0) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800377 r = EOF;
378 }
379 if (fp->_flags & __SMBF) free(fp->_bf._base);
380 if (HASUB(fp)) FREEUB(fp);
Elliott Hughes80e4c152017-07-21 13:57:55 -0700381 free_fgetln_buffer(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800382
Elliott Hughes2704bd12016-01-20 17:14:53 -0800383 // Poison this FILE so accesses after fclose will be obvious.
384 fp->_file = -1;
385 fp->_r = fp->_w = 0;
Elliott Hughes923f1652016-01-19 15:46:05 -0800386
Elliott Hughes2704bd12016-01-20 17:14:53 -0800387 // Release this FILE for reuse.
388 fp->_flags = 0;
389 return r;
Elliott Hughes923f1652016-01-19 15:46:05 -0800390}
391
Elliott Hughescceaf062016-07-29 16:31:52 -0700392int fileno_unlocked(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700393 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700394 int fd = fp->_file;
395 if (fd == -1) {
396 errno = EBADF;
397 return -1;
398 }
399 return fd;
400}
401
Elliott Hughes923f1652016-01-19 15:46:05 -0800402int fileno(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700403 CHECK_FP(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800404 ScopedFileLock sfl(fp);
405 return fileno_unlocked(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800406}
Elliott Hughes021335e2016-01-19 16:28:15 -0800407
Elliott Hughescceaf062016-07-29 16:31:52 -0700408void clearerr_unlocked(FILE* fp) {
409 return __sclearerr(fp);
410}
411
412void clearerr(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700413 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700414 ScopedFileLock sfl(fp);
415 clearerr_unlocked(fp);
416}
417
418int feof_unlocked(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700419 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700420 return ((fp->_flags & __SEOF) != 0);
Elliott Hughescceaf062016-07-29 16:31:52 -0700421}
422
423int feof(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700424 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700425 ScopedFileLock sfl(fp);
426 return feof_unlocked(fp);
427}
428
429int ferror_unlocked(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700430 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700431 return __sferror(fp);
432}
433
434int ferror(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700435 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700436 ScopedFileLock sfl(fp);
437 return ferror_unlocked(fp);
438}
439
Elliott Hughes37ad9592017-10-30 17:47:12 -0700440int __sflush(FILE* fp) {
441 // Flushing a read-only file is a no-op.
442 if ((fp->_flags & __SWR) == 0) return 0;
443
444 // Flushing a file without a buffer is a no-op.
445 unsigned char* p = fp->_bf._base;
446 if (p == nullptr) return 0;
447
448 // Set these immediately to avoid problems with longjmp and to allow
449 // exchange buffering (via setvbuf) in user write function.
450 int n = fp->_p - p;
451 fp->_p = p;
452 fp->_w = (fp->_flags & (__SLBF|__SNBF)) ? 0 : fp->_bf._size;
453
454 while (n > 0) {
455 int written = (*fp->_write)(fp->_cookie, reinterpret_cast<char*>(p), n);
456 if (written <= 0) {
457 fp->_flags |= __SERR;
458 return EOF;
459 }
460 n -= written, p += written;
461 }
462 return 0;
463}
464
465int __sflush_locked(FILE* fp) {
466 ScopedFileLock sfl(fp);
467 return __sflush(fp);
468}
469
Elliott Hughes021335e2016-01-19 16:28:15 -0800470int __sread(void* cookie, char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800471 FILE* fp = reinterpret_cast<FILE*>(cookie);
472 return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800473}
474
475int __swrite(void* cookie, const char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800476 FILE* fp = reinterpret_cast<FILE*>(cookie);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800477 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800478}
479
Elliott Hughes021335e2016-01-19 16:28:15 -0800480fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800481 FILE* fp = reinterpret_cast<FILE*>(cookie);
482 return TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
Elliott Hughes021335e2016-01-19 16:28:15 -0800483}
484
Elliott Hughes023c3072016-01-22 15:04:51 -0800485off64_t __sseek64(void* cookie, off64_t offset, int whence) {
486 FILE* fp = reinterpret_cast<FILE*>(cookie);
487 return TEMP_FAILURE_RETRY(lseek64(fp->_file, offset, whence));
488}
489
Elliott Hughes021335e2016-01-19 16:28:15 -0800490int __sclose(void* cookie) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800491 FILE* fp = reinterpret_cast<FILE*>(cookie);
492 return close(fp->_file);
493}
494
Elliott Hughes023c3072016-01-22 15:04:51 -0800495static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
496 // Use `_seek64` if set, but fall back to `_seek`.
497 if (_EXT(fp)->_seek64 != nullptr) {
498 return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence);
499 } else if (fp->_seek != nullptr) {
Elliott Hughes955426e2016-01-26 18:25:52 -0800500 off64_t result = (*fp->_seek)(fp->_cookie, offset, whence);
501#if !defined(__LP64__)
502 // Avoid sign extension if off64_t is larger than off_t.
503 if (result != -1) result &= 0xffffffff;
504#endif
505 return result;
Elliott Hughes023c3072016-01-22 15:04:51 -0800506 } else {
507 errno = ESPIPE;
508 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800509 }
Elliott Hughes2704bd12016-01-20 17:14:53 -0800510}
511
Elliott Hughes9677fab2016-01-25 15:50:59 -0800512static off64_t __ftello64_unlocked(FILE* fp) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800513 // Find offset of underlying I/O object, then adjust for buffered bytes.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800514 __sflush(fp); // May adjust seek offset on append stream.
Elliott Hughes33a8cb12017-07-25 18:06:46 -0700515
Elliott Hughes9677fab2016-01-25 15:50:59 -0800516 off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800517 if (result == -1) {
518 return -1;
519 }
520
521 if (fp->_flags & __SRD) {
522 // Reading. Any unread characters (including
523 // those from ungetc) cause the position to be
524 // smaller than that in the underlying object.
525 result -= fp->_r;
526 if (HASUB(fp)) result -= fp->_ur;
Elliott Hughes37ad9592017-10-30 17:47:12 -0700527 } else if (fp->_flags & __SWR && fp->_p != nullptr) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800528 // Writing. Any buffered characters cause the
529 // position to be greater than that in the
530 // underlying object.
531 result += fp->_p - fp->_bf._base;
532 }
533 return result;
534}
535
Elliott Hughes9677fab2016-01-25 15:50:59 -0800536int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800537 ScopedFileLock sfl(fp);
538
Elliott Hughes023c3072016-01-22 15:04:51 -0800539 // Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800540 // After this, whence is either SEEK_SET or SEEK_END.
541 if (whence == SEEK_CUR) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800542 fpos64_t current_offset = __ftello64_unlocked(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800543 if (current_offset == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800544 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800545 }
546 offset += current_offset;
547 whence = SEEK_SET;
548 } else if (whence != SEEK_SET && whence != SEEK_END) {
549 errno = EINVAL;
Elliott Hughes9677fab2016-01-25 15:50:59 -0800550 return -1;
551 }
552
553 // If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
554 if (off_t_bits == 32 && offset > LONG_MAX) {
555 errno = EOVERFLOW;
556 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800557 }
558
Elliott Hughes37ad9592017-10-30 17:47:12 -0700559 if (fp->_bf._base == nullptr) __smakebuf(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800560
561 // Flush unwritten data and attempt the seek.
Elliott Hughes023c3072016-01-22 15:04:51 -0800562 if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800563 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800564 }
565
566 // Success: clear EOF indicator and discard ungetc() data.
567 if (HASUB(fp)) FREEUB(fp);
568 fp->_p = fp->_bf._base;
569 fp->_r = 0;
570 /* fp->_w = 0; */ /* unnecessary (I think...) */
571 fp->_flags &= ~__SEOF;
572 return 0;
573}
574
Elliott Hughes9677fab2016-01-25 15:50:59 -0800575int fseeko(FILE* fp, off_t offset, int whence) {
Josh Gaod1620602017-10-05 13:48:08 -0700576 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800577 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
578 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
579}
580__strong_alias(fseek, fseeko);
581
582int fseeko64(FILE* fp, off64_t offset, int whence) {
Josh Gaod1620602017-10-05 13:48:08 -0700583 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800584 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
Elliott Hughes2704bd12016-01-20 17:14:53 -0800585}
586
Elliott Hughes9677fab2016-01-25 15:50:59 -0800587int fsetpos(FILE* fp, const fpos_t* pos) {
Josh Gaod1620602017-10-05 13:48:08 -0700588 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800589 return fseeko(fp, *pos, SEEK_SET);
590}
591
592int fsetpos64(FILE* fp, const fpos64_t* pos) {
Josh Gaod1620602017-10-05 13:48:08 -0700593 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800594 return fseeko64(fp, *pos, SEEK_SET);
595}
596
Elliott Hughes2704bd12016-01-20 17:14:53 -0800597off_t ftello(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700598 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800599 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
600 off64_t result = ftello64(fp);
601 if (result > LONG_MAX) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800602 errno = EOVERFLOW;
603 return -1;
604 }
Elliott Hughes9677fab2016-01-25 15:50:59 -0800605 return result;
606}
607__strong_alias(ftell, ftello);
608
609off64_t ftello64(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700610 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800611 ScopedFileLock sfl(fp);
612 return __ftello64_unlocked(fp);
Elliott Hughes021335e2016-01-19 16:28:15 -0800613}
Elliott Hughes023c3072016-01-22 15:04:51 -0800614
Elliott Hughes023c3072016-01-22 15:04:51 -0800615int fgetpos(FILE* fp, fpos_t* pos) {
Josh Gaod1620602017-10-05 13:48:08 -0700616 CHECK_FP(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800617 *pos = ftello(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800618 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800619}
620
Elliott Hughes9677fab2016-01-25 15:50:59 -0800621int fgetpos64(FILE* fp, fpos64_t* pos) {
Josh Gaod1620602017-10-05 13:48:08 -0700622 CHECK_FP(fp);
Elliott Hughes9677fab2016-01-25 15:50:59 -0800623 *pos = ftello64(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800624 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800625}
Elliott Hughes03e65eb2016-01-26 14:13:04 -0800626
627static FILE* __funopen(const void* cookie,
628 int (*read_fn)(void*, char*, int),
629 int (*write_fn)(void*, const char*, int),
630 int (*close_fn)(void*)) {
631 if (read_fn == nullptr && write_fn == nullptr) {
632 errno = EINVAL;
633 return nullptr;
634 }
635
636 FILE* fp = __sfp();
637 if (fp == nullptr) return nullptr;
638
639 if (read_fn != nullptr && write_fn != nullptr) {
640 fp->_flags = __SRW;
641 } else if (read_fn != nullptr) {
642 fp->_flags = __SRD;
643 } else if (write_fn != nullptr) {
644 fp->_flags = __SWR;
645 }
646
647 fp->_file = -1;
648 fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
649 fp->_read = read_fn;
650 fp->_write = write_fn;
651 fp->_close = close_fn;
652
653 return fp;
654}
655
656FILE* funopen(const void* cookie,
657 int (*read_fn)(void*, char*, int),
658 int (*write_fn)(void*, const char*, int),
659 fpos_t (*seek_fn)(void*, fpos_t, int),
660 int (*close_fn)(void*)) {
661 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
662 if (fp != nullptr) {
663 fp->_seek = seek_fn;
664 }
665 return fp;
666}
667
668FILE* funopen64(const void* cookie,
669 int (*read_fn)(void*, char*, int),
670 int (*write_fn)(void*, const char*, int),
671 fpos64_t (*seek_fn)(void*, fpos64_t, int),
672 int (*close_fn)(void*)) {
673 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
674 if (fp != nullptr) {
675 _EXT(fp)->_seek64 = seek_fn;
676 }
677 return fp;
678}
Elliott Hughes20788ae2016-06-09 15:16:32 -0700679
Elliott Hughes53cf3482016-08-09 13:06:41 -0700680int asprintf(char** s, const char* fmt, ...) {
681 PRINTF_IMPL(vasprintf(s, fmt, ap));
682}
683
Elliott Hughes20788ae2016-06-09 15:16:32 -0700684char* ctermid(char* s) {
685 return s ? strcpy(s, _PATH_TTY) : const_cast<char*>(_PATH_TTY);
686}
Elliott Hughescceaf062016-07-29 16:31:52 -0700687
Elliott Hughes70715da2016-08-01 16:35:17 -0700688int dprintf(int fd, const char* fmt, ...) {
689 PRINTF_IMPL(vdprintf(fd, fmt, ap));
690}
691
692int fprintf(FILE* fp, const char* fmt, ...) {
Josh Gaod1620602017-10-05 13:48:08 -0700693 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700694 PRINTF_IMPL(vfprintf(fp, fmt, ap));
695}
696
Elliott Hughescceaf062016-07-29 16:31:52 -0700697int fgetc(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700698 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700699 return getc(fp);
700}
701
Elliott Hughes37ad9592017-10-30 17:47:12 -0700702int fgetc_unlocked(FILE* fp) {
703 CHECK_FP(fp);
704 return getc_unlocked(fp);
705}
706
707/*
708 * Read at most n-1 characters from the given file.
709 * Stop when a newline has been read, or the count runs out.
710 * Return first argument, or NULL if no characters were read.
711 * Do not return NULL if n == 1.
712 */
713char* fgets(char* buf, int n, FILE* fp) __overloadable {
714 CHECK_FP(fp);
715 ScopedFileLock sfl(fp);
716 return fgets_unlocked(buf, n, fp);
717}
718
719char* fgets_unlocked(char* buf, int n, FILE* fp) {
720 if (n <= 0) {
721 errno = EINVAL;
722 return nullptr;
723 }
724
725 _SET_ORIENTATION(fp, -1);
726
727 char* s = buf;
728 n--; // Leave space for NUL.
729 while (n != 0) {
730 // If the buffer is empty, refill it.
731 if (fp->_r <= 0) {
732 if (__srefill(fp)) {
733 // EOF/error: stop with partial or no line.
734 if (s == buf) return nullptr;
735 break;
736 }
737 }
738 size_t len = fp->_r;
739 unsigned char* p = fp->_p;
740
741 // Scan through at most n bytes of the current buffer,
742 // looking for '\n'. If found, copy up to and including
743 // newline, and stop. Otherwise, copy entire chunk and loop.
744 if (len > static_cast<size_t>(n)) len = n;
745 unsigned char* t = static_cast<unsigned char*>(memchr(p, '\n', len));
746 if (t != nullptr) {
747 len = ++t - p;
748 fp->_r -= len;
749 fp->_p = t;
750 memcpy(s, p, len);
751 s[len] = '\0';
752 return buf;
753 }
754 fp->_r -= len;
755 fp->_p += len;
756 memcpy(s, p, len);
757 s += len;
758 n -= len;
759 }
760 *s = '\0';
761 return buf;
762}
763
Elliott Hughescceaf062016-07-29 16:31:52 -0700764int fputc(int c, FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700765 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700766 return putc(c, fp);
767}
768
Elliott Hughes37ad9592017-10-30 17:47:12 -0700769int fputc_unlocked(int c, FILE* fp) {
770 CHECK_FP(fp);
771 return putc_unlocked(c, fp);
772}
773
774int fputs(const char* s, FILE* fp) {
775 CHECK_FP(fp);
776 ScopedFileLock sfl(fp);
777 return fputs_unlocked(s, fp);
778}
779
780int fputs_unlocked(const char* s, FILE* fp) {
781 CHECK_FP(fp);
782 size_t length = strlen(s);
783 return (fwrite_unlocked(s, 1, length, fp) == length) ? 0 : EOF;
784}
785
Elliott Hughes70715da2016-08-01 16:35:17 -0700786int fscanf(FILE* fp, const char* fmt, ...) {
Josh Gaod1620602017-10-05 13:48:08 -0700787 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700788 PRINTF_IMPL(vfscanf(fp, fmt, ap));
789}
790
791int fwprintf(FILE* fp, const wchar_t* fmt, ...) {
Josh Gaod1620602017-10-05 13:48:08 -0700792 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700793 PRINTF_IMPL(vfwprintf(fp, fmt, ap));
794}
795
796int fwscanf(FILE* fp, const wchar_t* fmt, ...) {
Josh Gaod1620602017-10-05 13:48:08 -0700797 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700798 PRINTF_IMPL(vfwscanf(fp, fmt, ap));
799}
800
801int getc(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700802 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700803 ScopedFileLock sfl(fp);
804 return getc_unlocked(fp);
805}
806
807int getc_unlocked(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700808 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700809 return __sgetc(fp);
810}
811
812int getchar_unlocked() {
813 return getc_unlocked(stdin);
814}
815
816int getchar() {
817 return getc(stdin);
818}
819
Elliott Hughescceaf062016-07-29 16:31:52 -0700820ssize_t getline(char** buf, size_t* len, FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700821 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700822 return getdelim(buf, len, '\n', fp);
823}
824
825wint_t getwc(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700826 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700827 return fgetwc(fp);
828}
829
830wint_t getwchar() {
831 return fgetwc(stdin);
832}
833
Elliott Hughes37ad9592017-10-30 17:47:12 -0700834void perror(const char* msg) {
835 if (msg == nullptr) msg = "";
836 fprintf(stderr, "%s%s%s\n", msg, (*msg == '\0') ? "" : ": ", strerror(errno));
837}
838
Elliott Hughes70715da2016-08-01 16:35:17 -0700839int printf(const char* fmt, ...) {
840 PRINTF_IMPL(vfprintf(stdout, fmt, ap));
841}
842
843int putc(int c, FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700844 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700845 ScopedFileLock sfl(fp);
846 return putc_unlocked(c, fp);
847}
848
849int putc_unlocked(int c, FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700850 CHECK_FP(fp);
Elliott Hughes70715da2016-08-01 16:35:17 -0700851 if (cantwrite(fp)) {
852 errno = EBADF;
853 return EOF;
854 }
855 _SET_ORIENTATION(fp, -1);
856 if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && c != '\n')) {
857 return (*fp->_p++ = c);
858 }
859 return (__swbuf(c, fp));
860}
861
862int putchar(int c) {
863 return putc(c, stdout);
864}
865
866int putchar_unlocked(int c) {
867 return putc_unlocked(c, stdout);
868}
869
Elliott Hughes37ad9592017-10-30 17:47:12 -0700870int puts(const char* s) {
871 size_t length = strlen(s);
872 ScopedFileLock sfl(stdout);
873 return (fwrite_unlocked(s, 1, length, stdout) == length &&
874 putc_unlocked('\n', stdout) != EOF) ? 0 : EOF;
875}
876
Elliott Hughescceaf062016-07-29 16:31:52 -0700877wint_t putwc(wchar_t wc, FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700878 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700879 return fputwc(wc, fp);
880}
881
882wint_t putwchar(wchar_t wc) {
883 return fputwc(wc, stdout);
884}
885
Elliott Hughesd1f25a72016-08-05 15:53:03 -0700886int remove(const char* path) {
887 if (unlink(path) != -1) return 0;
888 if (errno != EISDIR) return -1;
889 return rmdir(path);
890}
891
Elliott Hughescceaf062016-07-29 16:31:52 -0700892void rewind(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700893 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700894 ScopedFileLock sfl(fp);
895 fseek(fp, 0, SEEK_SET);
896 clearerr_unlocked(fp);
897}
898
Elliott Hughes70715da2016-08-01 16:35:17 -0700899int scanf(const char* fmt, ...) {
900 PRINTF_IMPL(vfscanf(stdin, fmt, ap));
901}
902
Elliott Hughescceaf062016-07-29 16:31:52 -0700903void setbuf(FILE* fp, char* buf) {
Josh Gaod1620602017-10-05 13:48:08 -0700904 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700905 setbuffer(fp, buf, BUFSIZ);
906}
907
908void setbuffer(FILE* fp, char* buf, int size) {
Josh Gaod1620602017-10-05 13:48:08 -0700909 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700910 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
911}
912
913int setlinebuf(FILE* fp) {
Josh Gaod1620602017-10-05 13:48:08 -0700914 CHECK_FP(fp);
Elliott Hughescceaf062016-07-29 16:31:52 -0700915 return setvbuf(fp, nullptr, _IOLBF, 0);
916}
917
Elliott Hughes53cf3482016-08-09 13:06:41 -0700918int snprintf(char* s, size_t n, const char* fmt, ...) {
919 PRINTF_IMPL(vsnprintf(s, n, fmt, ap));
920}
921
922int sprintf(char* s, const char* fmt, ...) {
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700923 PRINTF_IMPL(vsprintf(s, fmt, ap));
Elliott Hughes53cf3482016-08-09 13:06:41 -0700924}
925
926int sscanf(const char* s, const char* fmt, ...) {
927 PRINTF_IMPL(vsscanf(s, fmt, ap));
928}
929
Elliott Hughes70715da2016-08-01 16:35:17 -0700930int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) {
931 PRINTF_IMPL(vswprintf(s, n, fmt, ap));
932}
933
934int swscanf(const wchar_t* s, const wchar_t* fmt, ...) {
935 PRINTF_IMPL(vswscanf(s, fmt, ap));
936}
937
Elliott Hughes618303c2017-11-02 16:58:44 -0700938int vfprintf(FILE* fp, const char* fmt, va_list ap) {
939 ScopedFileLock sfl(fp);
940 return __vfprintf(fp, fmt, ap);
941}
942
943int vfwprintf(FILE* fp, const wchar_t* fmt, va_list ap) {
944 ScopedFileLock sfl(fp);
945 return __vfwprintf(fp, fmt, ap);
946}
947
Elliott Hughescceaf062016-07-29 16:31:52 -0700948int vprintf(const char* fmt, va_list ap) {
949 return vfprintf(stdout, fmt, ap);
950}
951
952int vscanf(const char* fmt, va_list ap) {
953 return vfscanf(stdin, fmt, ap);
954}
955
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700956int vsnprintf(char* s, size_t n, const char* fmt, va_list ap) {
957 // stdio internals use int rather than size_t.
958 static_assert(INT_MAX <= SSIZE_MAX, "SSIZE_MAX too large to fit in int");
959
960 __check_count("vsnprintf", "size", n);
961
962 // Stdio internals do not deal correctly with zero length buffer.
963 char dummy;
964 if (n == 0) {
965 s = &dummy;
966 n = 1;
967 }
968
969 FILE f;
970 __sfileext fext;
971 _FILEEXT_SETUP(&f, &fext);
972 f._file = -1;
973 f._flags = __SWR | __SSTR;
974 f._bf._base = f._p = reinterpret_cast<unsigned char*>(s);
975 f._bf._size = f._w = n - 1;
976
977 int result = __vfprintf(&f, fmt, ap);
978 *f._p = '\0';
979 return result;
980}
981
Elliott Hughes53cf3482016-08-09 13:06:41 -0700982int vsprintf(char* s, const char* fmt, va_list ap) {
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700983 return vsnprintf(s, SSIZE_MAX, fmt, ap);
Elliott Hughes53cf3482016-08-09 13:06:41 -0700984}
985
Elliott Hughescceaf062016-07-29 16:31:52 -0700986int vwprintf(const wchar_t* fmt, va_list ap) {
987 return vfwprintf(stdout, fmt, ap);
988}
989
990int vwscanf(const wchar_t* fmt, va_list ap) {
991 return vfwscanf(stdin, fmt, ap);
992}
Elliott Hughes70715da2016-08-01 16:35:17 -0700993
994int wprintf(const wchar_t* fmt, ...) {
995 PRINTF_IMPL(vfwprintf(stdout, fmt, ap));
996}
997
998int wscanf(const wchar_t* fmt, ...) {
999 PRINTF_IMPL(vfwscanf(stdin, fmt, ap));
1000}
Dan Albert3037ea42016-10-06 15:46:45 -07001001
Elliott Hughes37ad9592017-10-30 17:47:12 -07001002static int fflush_all() {
1003 return _fwalk(__sflush_locked);
1004}
1005
1006int fflush(FILE* fp) {
1007 if (fp == nullptr) return fflush_all();
1008 ScopedFileLock sfl(fp);
1009 return fflush_unlocked(fp);
1010}
1011
1012int fflush_unlocked(FILE* fp) {
1013 if (fp == nullptr) return fflush_all();
1014 if ((fp->_flags & (__SWR | __SRW)) == 0) {
1015 errno = EBADF;
1016 return EOF;
1017 }
1018 return __sflush(fp);
1019}
1020
1021size_t fread(void* buf, size_t size, size_t count, FILE* fp) __overloadable {
1022 CHECK_FP(fp);
1023 ScopedFileLock sfl(fp);
1024 return fread_unlocked(buf, size, count, fp);
1025}
1026
1027size_t fread_unlocked(void* buf, size_t size, size_t count, FILE* fp) {
1028 CHECK_FP(fp);
1029
1030 size_t desired_total;
1031 if (__builtin_mul_overflow(size, count, &desired_total)) {
1032 errno = EOVERFLOW;
1033 fp->_flags |= __SERR;
1034 return 0;
1035 }
1036
1037 size_t total = desired_total;
1038 if (total == 0) return 0;
1039
1040 _SET_ORIENTATION(fp, -1);
1041
1042 // TODO: how can this ever happen?!
1043 if (fp->_r < 0) fp->_r = 0;
1044
1045 // Ensure _bf._size is valid.
1046 if (fp->_bf._base == nullptr) __smakebuf(fp);
1047
1048 char* dst = static_cast<char*>(buf);
1049
1050 while (total > 0) {
1051 // Copy data out of the buffer.
1052 size_t buffered_bytes = MIN(static_cast<size_t>(fp->_r), total);
1053 memcpy(dst, fp->_p, buffered_bytes);
1054 fp->_p += buffered_bytes;
1055 fp->_r -= buffered_bytes;
1056 dst += buffered_bytes;
1057 total -= buffered_bytes;
1058
1059 // Are we done?
1060 if (total == 0) goto out;
1061
1062 // Do we have so much more to read that we should avoid copying it through the buffer?
1063 if (total > static_cast<size_t>(fp->_bf._size)) break;
1064
1065 // Less than a buffer to go, so refill the buffer and go around the loop again.
1066 if (__srefill(fp)) goto out;
1067 }
1068
1069 // Read directly into the caller's buffer.
1070 while (total > 0) {
1071 ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total);
1072 if (bytes_read <= 0) {
1073 fp->_flags |= (bytes_read == 0) ? __SEOF : __SERR;
1074 break;
1075 }
1076 dst += bytes_read;
1077 total -= bytes_read;
1078 }
1079
1080out:
1081 return ((desired_total - total) / size);
1082}
1083
1084size_t fwrite(const void* buf, size_t size, size_t count, FILE* fp) {
1085 CHECK_FP(fp);
1086 ScopedFileLock sfl(fp);
1087 return fwrite_unlocked(buf, size, count, fp);
1088}
1089
1090size_t fwrite_unlocked(const void* buf, size_t size, size_t count, FILE* fp) {
1091 CHECK_FP(fp);
1092
1093 size_t n;
1094 if (__builtin_mul_overflow(size, count, &n)) {
1095 errno = EOVERFLOW;
1096 fp->_flags |= __SERR;
1097 return 0;
1098 }
1099
1100 if (n == 0) return 0;
1101
1102 __siov iov = { .iov_base = const_cast<void*>(buf), .iov_len = n };
1103 __suio uio = { .uio_iov = &iov, .uio_iovcnt = 1, .uio_resid = n };
1104
1105 _SET_ORIENTATION(fp, -1);
1106
1107 // The usual case is success (__sfvwrite returns 0); skip the divide if this happens,
1108 // since divides are generally slow.
1109 return (__sfvwrite(fp, &uio) == 0) ? count : ((n - uio.uio_resid) / size);
1110}
1111
Dan Albert3037ea42016-10-06 15:46:45 -07001112namespace {
1113
1114namespace phony {
1115#include <bits/struct_file.h>
1116}
1117
1118static_assert(sizeof(::__sFILE) == sizeof(phony::__sFILE),
1119 "size mismatch between `struct __sFILE` implementation and public stub");
1120static_assert(alignof(::__sFILE) == alignof(phony::__sFILE),
1121 "alignment mismatch between `struct __sFILE` implementation and public stub");
1122
1123}