blob: c6736118ecfe9f5370d205eccebc3df9b515d1b4 [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 Hughes023c3072016-01-22 15:04:51 -080049#include "private/ErrnoRestorer.h"
Elliott Hughes6a03abc2014-11-03 12:32:17 -080050#include "private/thread_private.h"
51
52#define ALIGNBYTES (sizeof(uintptr_t) - 1)
53#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
Calin Juravlec20de902014-03-20 15:21:32 +000054
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055#define NDYNAMIC 10 /* add ten more whenever necessary */
56
Elliott Hughes70715da2016-08-01 16:35:17 -070057#define PRINTF_IMPL(expr) \
58 va_list ap; \
59 va_start(ap, fmt); \
60 int result = (expr); \
61 va_end(ap); \
62 return result;
63
Elliott Hughes023c3072016-01-22 15:04:51 -080064#define std(flags, file) \
65 {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,nullptr,__swrite, \
66 {(unsigned char *)(__sFext+file), 0},nullptr,0,{0},{0},{0,0},0,0}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080067
Kenny Rootf5823402011-02-12 07:13:44 -080068_THREAD_PRIVATE_MUTEX(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080069
Elliott Hughes29ee6392015-12-07 11:07:15 -080070// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
71#define SBUF_INIT {0,0}
72#if defined(__LP64__)
73#define MBSTATE_T_INIT {{0},{0}}
74#else
75#define MBSTATE_T_INIT {{0}}
76#endif
77#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
78
Elliott Hughesbb46afd2015-12-04 18:03:12 -080079static struct __sfileext __sFext[3] = {
Elliott Hughes023c3072016-01-22 15:04:51 -080080 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
81 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
82 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080083};
Elliott Hughesf0141df2015-10-12 12:44:23 -070084
85// __sF is exported for backwards compatibility. Until M, we didn't have symbols
86// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080088 std(__SRD, STDIN_FILENO),
89 std(__SWR, STDOUT_FILENO),
90 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091};
Elliott Hughesf0141df2015-10-12 12:44:23 -070092
Elliott Hughes168667c2014-11-14 14:42:59 -080093FILE* stdin = &__sF[0];
94FILE* stdout = &__sF[1];
95FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080096
Elliott Hughesbb46afd2015-12-04 18:03:12 -080097struct glue __sglue = { NULL, 3, __sF };
98static struct glue* lastglue = &__sglue;
99
Elliott Hughes2704bd12016-01-20 17:14:53 -0800100class ScopedFileLock {
101 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -0700102 explicit ScopedFileLock(FILE* fp) : fp_(fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800103 FLOCKFILE(fp_);
104 }
105 ~ScopedFileLock() {
106 FUNLOCKFILE(fp_);
107 }
108
109 private:
110 FILE* fp_;
111};
112
Elliott Hughes021335e2016-01-19 16:28:15 -0800113static glue* moreglue(int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800114 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800115
Elliott Hughes2704bd12016-01-20 17:14:53 -0800116 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
117 if (data == nullptr) return nullptr;
Elliott Hughes021335e2016-01-19 16:28:15 -0800118
Elliott Hughes2704bd12016-01-20 17:14:53 -0800119 glue* g = reinterpret_cast<glue*>(data);
120 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
121 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
122 g->next = NULL;
123 g->niobs = n;
124 g->iobs = p;
125 while (--n >= 0) {
126 *p = empty;
127 _FILEEXT_SETUP(p, pext);
128 p++;
129 pext++;
130 }
131 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800132}
133
134/*
135 * Find a free FILE for fopen et al.
136 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800137FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800138 FILE *fp;
139 int n;
140 struct glue *g;
141
Kenny Rootf5823402011-02-12 07:13:44 -0800142 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
143 for (g = &__sglue; g != NULL; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800144 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
145 if (fp->_flags == 0)
146 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800147 }
Kenny Rootf5823402011-02-12 07:13:44 -0800148
149 /* release lock while mallocing */
150 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
151 if ((g = moreglue(NDYNAMIC)) == NULL)
152 return (NULL);
153 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
154 lastglue->next = g;
155 lastglue = g;
156 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157found:
158 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800159 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800160 fp->_p = NULL; /* no current pointer */
161 fp->_w = 0; /* nothing to read or write */
162 fp->_r = 0;
163 fp->_bf._base = NULL; /* no buffer */
164 fp->_bf._size = 0;
165 fp->_lbfsize = 0; /* not line buffered */
166 fp->_file = -1; /* no file */
Elliott Hughes023c3072016-01-22 15:04:51 -0800167
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168 fp->_lb._base = NULL; /* no line buffer */
169 fp->_lb._size = 0;
170 _FILEEXT_INIT(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800171
172 // Caller sets cookie, _read/_write etc.
173 // We explicitly clear _seek and _seek64 to prevent subtle bugs.
174 fp->_seek = nullptr;
175 _EXT(fp)->_seek64 = nullptr;
176
177 return fp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800178}
179
Elliott Hughes021335e2016-01-19 16:28:15 -0800180extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800181 // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
182 _fwalk(__sflush);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800183}
Elliott Hughes923f1652016-01-19 15:46:05 -0800184
Elliott Hughes023c3072016-01-22 15:04:51 -0800185static FILE* __fopen(int fd, int flags) {
186#if !defined(__LP64__)
187 if (fd > SHRT_MAX) {
188 errno = EMFILE;
189 return nullptr;
190 }
191#endif
192
193 FILE* fp = __sfp();
194 if (fp != nullptr) {
195 fp->_file = fd;
196 fp->_flags = flags;
197 fp->_cookie = fp;
198 fp->_read = __sread;
199 fp->_write = __swrite;
200 fp->_close = __sclose;
201 _EXT(fp)->_seek64 = __sseek64;
202 }
203 return fp;
204}
205
206FILE* fopen(const char* file, const char* mode) {
207 int oflags;
208 int flags = __sflags(mode, &oflags);
209 if (flags == 0) return nullptr;
210
211 int fd = open(file, oflags, DEFFILEMODE);
212 if (fd == -1) {
213 return nullptr;
214 }
215
216 FILE* fp = __fopen(fd, flags);
217 if (fp == nullptr) {
218 ErrnoRestorer errno_restorer;
219 close(fd);
220 return nullptr;
221 }
222
223 // When opening in append mode, even though we use O_APPEND,
224 // we need to seek to the end so that ftell() gets the right
225 // answer. If the user then alters the seek pointer, or
226 // the file extends, this will fail, but there is not much
227 // we can do about this. (We could set __SAPP and check in
228 // fseek and ftell.)
229 // TODO: check in __sseek instead.
230 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
231
232 return fp;
233}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800234__strong_alias(fopen64, fopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800235
236FILE* fdopen(int fd, const char* mode) {
237 int oflags;
238 int flags = __sflags(mode, &oflags);
239 if (flags == 0) return nullptr;
240
241 // Make sure the mode the user wants is a subset of the actual mode.
242 int fdflags = fcntl(fd, F_GETFL, 0);
243 if (fdflags < 0) return nullptr;
244 int tmp = fdflags & O_ACCMODE;
245 if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
246 errno = EINVAL;
247 return nullptr;
248 }
249
250 // If opened for appending, but underlying descriptor does not have
251 // O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
252 // end before each write.
253 // TODO: use fcntl(2) to set O_APPEND instead.
254 if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) flags |= __SAPP;
255
256 // If close-on-exec was requested, then turn it on if not already.
257 if ((oflags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
258 fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
259 }
260
261 return __fopen(fd, flags);
262}
263
264// Re-direct an existing, open (probably) file to some other file.
265// ANSI is written such that the original file gets closed if at
266// all possible, no matter what.
267// TODO: rewrite this mess completely.
268FILE* freopen(const char* file, const char* mode, FILE* fp) {
269 int oflags;
270 int flags = __sflags(mode, &oflags);
271 if (flags == 0) {
272 fclose(fp);
273 return nullptr;
274 }
275
276 ScopedFileLock sfl(fp);
277
278 // There are actually programs that depend on being able to "freopen"
279 // descriptors that weren't originally open. Keep this from breaking.
280 // Remember whether the stream was open to begin with, and which file
281 // descriptor (if any) was associated with it. If it was attached to
282 // a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
283 // should work. This is unnecessary if it was not a Unix file.
284 int isopen, wantfd;
285 if (fp->_flags == 0) {
286 fp->_flags = __SEOF; // Hold on to it.
287 isopen = 0;
288 wantfd = -1;
289 } else {
290 // Flush the stream; ANSI doesn't require this.
291 if (fp->_flags & __SWR) __sflush(fp);
292
293 // If close is NULL, closing is a no-op, hence pointless.
294 isopen = fp->_close != NULL;
295 if ((wantfd = fp->_file) < 0 && isopen) {
296 (*fp->_close)(fp->_cookie);
297 isopen = 0;
298 }
299 }
300
301 // Get a new descriptor to refer to the new file.
302 int fd = open(file, oflags, DEFFILEMODE);
303 if (fd < 0 && isopen) {
304 // If out of fd's close the old one and try again.
305 if (errno == ENFILE || errno == EMFILE) {
306 (*fp->_close)(fp->_cookie);
307 isopen = 0;
308 fd = open(file, oflags, DEFFILEMODE);
309 }
310 }
311
312 int sverrno = errno;
313
314 // Finish closing fp. Even if the open succeeded above, we cannot
315 // keep fp->_base: it may be the wrong size. This loses the effect
316 // of any setbuffer calls, but stdio has always done this before.
317 if (isopen && fd != wantfd) (*fp->_close)(fp->_cookie);
318 if (fp->_flags & __SMBF) free(fp->_bf._base);
319 fp->_w = 0;
320 fp->_r = 0;
321 fp->_p = NULL;
322 fp->_bf._base = NULL;
323 fp->_bf._size = 0;
324 fp->_lbfsize = 0;
325 if (HASUB(fp)) FREEUB(fp);
326 _UB(fp)._size = 0;
327 WCIO_FREE(fp);
328 if (HASLB(fp)) FREELB(fp);
329 fp->_lb._size = 0;
330
331 if (fd < 0) { // Did not get it after all.
332 fp->_flags = 0; // Release.
333 errno = sverrno; // Restore errno in case _close clobbered it.
334 return nullptr;
335 }
336
337 // If reopening something that was open before on a real file, try
338 // to maintain the descriptor. Various C library routines (perror)
339 // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
340 if (wantfd >= 0 && fd != wantfd) {
341 if (dup3(fd, wantfd, oflags & O_CLOEXEC) >= 0) {
342 close(fd);
343 fd = wantfd;
344 }
345 }
346
347 // _file is only a short.
348 if (fd > SHRT_MAX) {
349 fp->_flags = 0; // Release.
350 errno = EMFILE;
351 return nullptr;
352 }
353
354 fp->_flags = flags;
355 fp->_file = fd;
356 fp->_cookie = fp;
357 fp->_read = __sread;
358 fp->_write = __swrite;
359 fp->_close = __sclose;
360 _EXT(fp)->_seek64 = __sseek64;
361
362 // When opening in append mode, even though we use O_APPEND,
363 // we need to seek to the end so that ftell() gets the right
364 // answer. If the user then alters the seek pointer, or
365 // the file extends, this will fail, but there is not much
366 // we can do about this. (We could set __SAPP and check in
367 // fseek and ftell.)
368 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
369 return fp;
370}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800371__strong_alias(freopen64, freopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800372
Elliott Hughes923f1652016-01-19 15:46:05 -0800373int fclose(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800374 if (fp->_flags == 0) {
375 // Already freed!
376 errno = EBADF;
377 return EOF;
378 }
Elliott Hughes923f1652016-01-19 15:46:05 -0800379
Elliott Hughes2704bd12016-01-20 17:14:53 -0800380 ScopedFileLock sfl(fp);
381 WCIO_FREE(fp);
382 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
383 if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
384 r = EOF;
385 }
386 if (fp->_flags & __SMBF) free(fp->_bf._base);
387 if (HASUB(fp)) FREEUB(fp);
388 if (HASLB(fp)) FREELB(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800389
Elliott Hughes2704bd12016-01-20 17:14:53 -0800390 // Poison this FILE so accesses after fclose will be obvious.
391 fp->_file = -1;
392 fp->_r = fp->_w = 0;
Elliott Hughes923f1652016-01-19 15:46:05 -0800393
Elliott Hughes2704bd12016-01-20 17:14:53 -0800394 // Release this FILE for reuse.
395 fp->_flags = 0;
396 return r;
Elliott Hughes923f1652016-01-19 15:46:05 -0800397}
398
Elliott Hughescceaf062016-07-29 16:31:52 -0700399int fileno_unlocked(FILE* fp) {
400 int fd = fp->_file;
401 if (fd == -1) {
402 errno = EBADF;
403 return -1;
404 }
405 return fd;
406}
407
Elliott Hughes923f1652016-01-19 15:46:05 -0800408int fileno(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800409 ScopedFileLock sfl(fp);
410 return fileno_unlocked(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800411}
Elliott Hughes021335e2016-01-19 16:28:15 -0800412
Elliott Hughescceaf062016-07-29 16:31:52 -0700413void clearerr_unlocked(FILE* fp) {
414 return __sclearerr(fp);
415}
416
417void clearerr(FILE* fp) {
418 ScopedFileLock sfl(fp);
419 clearerr_unlocked(fp);
420}
421
422int feof_unlocked(FILE* fp) {
Elliott Hughes70715da2016-08-01 16:35:17 -0700423 return ((fp->_flags & __SEOF) != 0);
Elliott Hughescceaf062016-07-29 16:31:52 -0700424}
425
426int feof(FILE* fp) {
427 ScopedFileLock sfl(fp);
428 return feof_unlocked(fp);
429}
430
431int ferror_unlocked(FILE* fp) {
432 return __sferror(fp);
433}
434
435int ferror(FILE* fp) {
436 ScopedFileLock sfl(fp);
437 return ferror_unlocked(fp);
438}
439
Elliott Hughes021335e2016-01-19 16:28:15 -0800440int __sread(void* cookie, char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800441 FILE* fp = reinterpret_cast<FILE*>(cookie);
442 return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800443}
444
445int __swrite(void* cookie, const char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800446 FILE* fp = reinterpret_cast<FILE*>(cookie);
447 if (fp->_flags & __SAPP) {
448 // The FILE* is in append mode, but the underlying fd doesn't have O_APPEND set.
449 // We need to seek manually.
Elliott Hughes023c3072016-01-22 15:04:51 -0800450 // TODO: use fcntl(2) to set O_APPEND in fdopen(3) instead?
Elliott Hughes2704bd12016-01-20 17:14:53 -0800451 TEMP_FAILURE_RETRY(lseek64(fp->_file, 0, SEEK_END));
452 }
453 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800454}
455
Elliott Hughes021335e2016-01-19 16:28:15 -0800456fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800457 FILE* fp = reinterpret_cast<FILE*>(cookie);
458 return TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
Elliott Hughes021335e2016-01-19 16:28:15 -0800459}
460
Elliott Hughes023c3072016-01-22 15:04:51 -0800461off64_t __sseek64(void* cookie, off64_t offset, int whence) {
462 FILE* fp = reinterpret_cast<FILE*>(cookie);
463 return TEMP_FAILURE_RETRY(lseek64(fp->_file, offset, whence));
464}
465
Elliott Hughes021335e2016-01-19 16:28:15 -0800466int __sclose(void* cookie) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800467 FILE* fp = reinterpret_cast<FILE*>(cookie);
468 return close(fp->_file);
469}
470
Elliott Hughes023c3072016-01-22 15:04:51 -0800471static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
472 // Use `_seek64` if set, but fall back to `_seek`.
473 if (_EXT(fp)->_seek64 != nullptr) {
474 return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence);
475 } else if (fp->_seek != nullptr) {
Elliott Hughes955426e2016-01-26 18:25:52 -0800476 off64_t result = (*fp->_seek)(fp->_cookie, offset, whence);
477#if !defined(__LP64__)
478 // Avoid sign extension if off64_t is larger than off_t.
479 if (result != -1) result &= 0xffffffff;
480#endif
481 return result;
Elliott Hughes023c3072016-01-22 15:04:51 -0800482 } else {
483 errno = ESPIPE;
484 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800485 }
Elliott Hughes2704bd12016-01-20 17:14:53 -0800486}
487
Elliott Hughes9677fab2016-01-25 15:50:59 -0800488static off64_t __ftello64_unlocked(FILE* fp) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800489 // Find offset of underlying I/O object, then adjust for buffered bytes.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800490 __sflush(fp); // May adjust seek offset on append stream.
Elliott Hughes9677fab2016-01-25 15:50:59 -0800491 off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800492 if (result == -1) {
493 return -1;
494 }
495
496 if (fp->_flags & __SRD) {
497 // Reading. Any unread characters (including
498 // those from ungetc) cause the position to be
499 // smaller than that in the underlying object.
500 result -= fp->_r;
501 if (HASUB(fp)) result -= fp->_ur;
502 } else if (fp->_flags & __SWR && fp->_p != NULL) {
503 // Writing. Any buffered characters cause the
504 // position to be greater than that in the
505 // underlying object.
506 result += fp->_p - fp->_bf._base;
507 }
508 return result;
509}
510
Elliott Hughes9677fab2016-01-25 15:50:59 -0800511int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800512 ScopedFileLock sfl(fp);
513
Elliott Hughes023c3072016-01-22 15:04:51 -0800514 // Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800515 // After this, whence is either SEEK_SET or SEEK_END.
516 if (whence == SEEK_CUR) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800517 fpos64_t current_offset = __ftello64_unlocked(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800518 if (current_offset == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800519 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800520 }
521 offset += current_offset;
522 whence = SEEK_SET;
523 } else if (whence != SEEK_SET && whence != SEEK_END) {
524 errno = EINVAL;
Elliott Hughes9677fab2016-01-25 15:50:59 -0800525 return -1;
526 }
527
528 // If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
529 if (off_t_bits == 32 && offset > LONG_MAX) {
530 errno = EOVERFLOW;
531 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800532 }
533
534 if (fp->_bf._base == NULL) __smakebuf(fp);
535
536 // Flush unwritten data and attempt the seek.
Elliott Hughes023c3072016-01-22 15:04:51 -0800537 if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800538 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800539 }
540
541 // Success: clear EOF indicator and discard ungetc() data.
542 if (HASUB(fp)) FREEUB(fp);
543 fp->_p = fp->_bf._base;
544 fp->_r = 0;
545 /* fp->_w = 0; */ /* unnecessary (I think...) */
546 fp->_flags &= ~__SEOF;
547 return 0;
548}
549
Elliott Hughes9677fab2016-01-25 15:50:59 -0800550int fseeko(FILE* fp, off_t offset, int whence) {
551 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
552 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
553}
554__strong_alias(fseek, fseeko);
555
556int fseeko64(FILE* fp, off64_t offset, int whence) {
557 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
Elliott Hughes2704bd12016-01-20 17:14:53 -0800558}
559
Elliott Hughes9677fab2016-01-25 15:50:59 -0800560int fsetpos(FILE* fp, const fpos_t* pos) {
561 return fseeko(fp, *pos, SEEK_SET);
562}
563
564int fsetpos64(FILE* fp, const fpos64_t* pos) {
565 return fseeko64(fp, *pos, SEEK_SET);
566}
567
Elliott Hughes2704bd12016-01-20 17:14:53 -0800568off_t ftello(FILE* fp) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800569 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
570 off64_t result = ftello64(fp);
571 if (result > LONG_MAX) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800572 errno = EOVERFLOW;
573 return -1;
574 }
Elliott Hughes9677fab2016-01-25 15:50:59 -0800575 return result;
576}
577__strong_alias(ftell, ftello);
578
579off64_t ftello64(FILE* fp) {
580 ScopedFileLock sfl(fp);
581 return __ftello64_unlocked(fp);
Elliott Hughes021335e2016-01-19 16:28:15 -0800582}
Elliott Hughes023c3072016-01-22 15:04:51 -0800583
Elliott Hughes023c3072016-01-22 15:04:51 -0800584int fgetpos(FILE* fp, fpos_t* pos) {
585 *pos = ftello(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800586 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800587}
588
Elliott Hughes9677fab2016-01-25 15:50:59 -0800589int fgetpos64(FILE* fp, fpos64_t* pos) {
590 *pos = ftello64(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800591 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800592}
Elliott Hughes03e65eb2016-01-26 14:13:04 -0800593
594static FILE* __funopen(const void* cookie,
595 int (*read_fn)(void*, char*, int),
596 int (*write_fn)(void*, const char*, int),
597 int (*close_fn)(void*)) {
598 if (read_fn == nullptr && write_fn == nullptr) {
599 errno = EINVAL;
600 return nullptr;
601 }
602
603 FILE* fp = __sfp();
604 if (fp == nullptr) return nullptr;
605
606 if (read_fn != nullptr && write_fn != nullptr) {
607 fp->_flags = __SRW;
608 } else if (read_fn != nullptr) {
609 fp->_flags = __SRD;
610 } else if (write_fn != nullptr) {
611 fp->_flags = __SWR;
612 }
613
614 fp->_file = -1;
615 fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
616 fp->_read = read_fn;
617 fp->_write = write_fn;
618 fp->_close = close_fn;
619
620 return fp;
621}
622
623FILE* funopen(const void* cookie,
624 int (*read_fn)(void*, char*, int),
625 int (*write_fn)(void*, const char*, int),
626 fpos_t (*seek_fn)(void*, fpos_t, int),
627 int (*close_fn)(void*)) {
628 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
629 if (fp != nullptr) {
630 fp->_seek = seek_fn;
631 }
632 return fp;
633}
634
635FILE* funopen64(const void* cookie,
636 int (*read_fn)(void*, char*, int),
637 int (*write_fn)(void*, const char*, int),
638 fpos64_t (*seek_fn)(void*, fpos64_t, int),
639 int (*close_fn)(void*)) {
640 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
641 if (fp != nullptr) {
642 _EXT(fp)->_seek64 = seek_fn;
643 }
644 return fp;
645}
Elliott Hughes20788ae2016-06-09 15:16:32 -0700646
Elliott Hughes53cf3482016-08-09 13:06:41 -0700647int asprintf(char** s, const char* fmt, ...) {
648 PRINTF_IMPL(vasprintf(s, fmt, ap));
649}
650
Elliott Hughes20788ae2016-06-09 15:16:32 -0700651char* ctermid(char* s) {
652 return s ? strcpy(s, _PATH_TTY) : const_cast<char*>(_PATH_TTY);
653}
Elliott Hughescceaf062016-07-29 16:31:52 -0700654
Elliott Hughes70715da2016-08-01 16:35:17 -0700655int dprintf(int fd, const char* fmt, ...) {
656 PRINTF_IMPL(vdprintf(fd, fmt, ap));
657}
658
659int fprintf(FILE* fp, const char* fmt, ...) {
660 PRINTF_IMPL(vfprintf(fp, fmt, ap));
661}
662
Elliott Hughescceaf062016-07-29 16:31:52 -0700663int fgetc(FILE* fp) {
664 return getc(fp);
665}
666
667int fputc(int c, FILE* fp) {
668 return putc(c, fp);
669}
670
Elliott Hughes70715da2016-08-01 16:35:17 -0700671int fscanf(FILE* fp, const char* fmt, ...) {
672 PRINTF_IMPL(vfscanf(fp, fmt, ap));
673}
674
675int fwprintf(FILE* fp, const wchar_t* fmt, ...) {
676 PRINTF_IMPL(vfwprintf(fp, fmt, ap));
677}
678
679int fwscanf(FILE* fp, const wchar_t* fmt, ...) {
680 PRINTF_IMPL(vfwscanf(fp, fmt, ap));
681}
682
683int getc(FILE* fp) {
684 ScopedFileLock sfl(fp);
685 return getc_unlocked(fp);
686}
687
688int getc_unlocked(FILE* fp) {
689 return __sgetc(fp);
690}
691
692int getchar_unlocked() {
693 return getc_unlocked(stdin);
694}
695
696int getchar() {
697 return getc(stdin);
698}
699
Elliott Hughescceaf062016-07-29 16:31:52 -0700700ssize_t getline(char** buf, size_t* len, FILE* fp) {
701 return getdelim(buf, len, '\n', fp);
702}
703
704wint_t getwc(FILE* fp) {
705 return fgetwc(fp);
706}
707
708wint_t getwchar() {
709 return fgetwc(stdin);
710}
711
Elliott Hughes70715da2016-08-01 16:35:17 -0700712int printf(const char* fmt, ...) {
713 PRINTF_IMPL(vfprintf(stdout, fmt, ap));
714}
715
716int putc(int c, FILE* fp) {
717 ScopedFileLock sfl(fp);
718 return putc_unlocked(c, fp);
719}
720
721int putc_unlocked(int c, FILE* fp) {
722 if (cantwrite(fp)) {
723 errno = EBADF;
724 return EOF;
725 }
726 _SET_ORIENTATION(fp, -1);
727 if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && c != '\n')) {
728 return (*fp->_p++ = c);
729 }
730 return (__swbuf(c, fp));
731}
732
733int putchar(int c) {
734 return putc(c, stdout);
735}
736
737int putchar_unlocked(int c) {
738 return putc_unlocked(c, stdout);
739}
740
Elliott Hughescceaf062016-07-29 16:31:52 -0700741wint_t putwc(wchar_t wc, FILE* fp) {
742 return fputwc(wc, fp);
743}
744
745wint_t putwchar(wchar_t wc) {
746 return fputwc(wc, stdout);
747}
748
Elliott Hughesd1f25a72016-08-05 15:53:03 -0700749int remove(const char* path) {
750 if (unlink(path) != -1) return 0;
751 if (errno != EISDIR) return -1;
752 return rmdir(path);
753}
754
Elliott Hughescceaf062016-07-29 16:31:52 -0700755void rewind(FILE* fp) {
756 ScopedFileLock sfl(fp);
757 fseek(fp, 0, SEEK_SET);
758 clearerr_unlocked(fp);
759}
760
Elliott Hughes70715da2016-08-01 16:35:17 -0700761int scanf(const char* fmt, ...) {
762 PRINTF_IMPL(vfscanf(stdin, fmt, ap));
763}
764
Elliott Hughescceaf062016-07-29 16:31:52 -0700765void setbuf(FILE* fp, char* buf) {
766 setbuffer(fp, buf, BUFSIZ);
767}
768
769void setbuffer(FILE* fp, char* buf, int size) {
770 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
771}
772
773int setlinebuf(FILE* fp) {
774 return setvbuf(fp, nullptr, _IOLBF, 0);
775}
776
Elliott Hughes53cf3482016-08-09 13:06:41 -0700777int snprintf(char* s, size_t n, const char* fmt, ...) {
778 PRINTF_IMPL(vsnprintf(s, n, fmt, ap));
779}
780
781int sprintf(char* s, const char* fmt, ...) {
782 PRINTF_IMPL(vsnprintf(s, INT_MAX, fmt, ap));
783}
784
785int sscanf(const char* s, const char* fmt, ...) {
786 PRINTF_IMPL(vsscanf(s, fmt, ap));
787}
788
Elliott Hughes70715da2016-08-01 16:35:17 -0700789int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) {
790 PRINTF_IMPL(vswprintf(s, n, fmt, ap));
791}
792
793int swscanf(const wchar_t* s, const wchar_t* fmt, ...) {
794 PRINTF_IMPL(vswscanf(s, fmt, ap));
795}
796
Elliott Hughescceaf062016-07-29 16:31:52 -0700797int vprintf(const char* fmt, va_list ap) {
798 return vfprintf(stdout, fmt, ap);
799}
800
801int vscanf(const char* fmt, va_list ap) {
802 return vfscanf(stdin, fmt, ap);
803}
804
Elliott Hughes53cf3482016-08-09 13:06:41 -0700805int vsprintf(char* s, const char* fmt, va_list ap) {
806 return vsnprintf(s, INT_MAX, fmt, ap);
807}
808
Elliott Hughescceaf062016-07-29 16:31:52 -0700809int vwprintf(const wchar_t* fmt, va_list ap) {
810 return vfwprintf(stdout, fmt, ap);
811}
812
813int vwscanf(const wchar_t* fmt, va_list ap) {
814 return vfwscanf(stdin, fmt, ap);
815}
Elliott Hughes70715da2016-08-01 16:35:17 -0700816
817int wprintf(const wchar_t* fmt, ...) {
818 PRINTF_IMPL(vfwprintf(stdout, fmt, ap));
819}
820
821int wscanf(const wchar_t* fmt, ...) {
822 PRINTF_IMPL(vfwscanf(stdin, fmt, ap));
823}