blob: cd4be2e76ac28ed79573b98335630f5c9b7fae26 [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 Hughes29ee6392015-12-07 11:07:15 -080071// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
72#define SBUF_INIT {0,0}
73#if defined(__LP64__)
74#define MBSTATE_T_INIT {{0},{0}}
75#else
76#define MBSTATE_T_INIT {{0}}
77#endif
78#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
79
Elliott Hughesbb46afd2015-12-04 18:03:12 -080080static struct __sfileext __sFext[3] = {
Elliott Hughes023c3072016-01-22 15:04:51 -080081 { 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 },
83 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080084};
Elliott Hughesf0141df2015-10-12 12:44:23 -070085
86// __sF is exported for backwards compatibility. Until M, we didn't have symbols
87// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080089 std(__SRD, STDIN_FILENO),
90 std(__SWR, STDOUT_FILENO),
91 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080092};
Elliott Hughesf0141df2015-10-12 12:44:23 -070093
Elliott Hughes168667c2014-11-14 14:42:59 -080094FILE* stdin = &__sF[0];
95FILE* stdout = &__sF[1];
96FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080097
Elliott Hughesbb46afd2015-12-04 18:03:12 -080098struct glue __sglue = { NULL, 3, __sF };
99static struct glue* lastglue = &__sglue;
100
Elliott Hughes2704bd12016-01-20 17:14:53 -0800101class ScopedFileLock {
102 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -0700103 explicit ScopedFileLock(FILE* fp) : fp_(fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800104 FLOCKFILE(fp_);
105 }
106 ~ScopedFileLock() {
107 FUNLOCKFILE(fp_);
108 }
109
110 private:
111 FILE* fp_;
112};
113
Elliott Hughes021335e2016-01-19 16:28:15 -0800114static glue* moreglue(int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800115 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800116
Elliott Hughes2704bd12016-01-20 17:14:53 -0800117 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
118 if (data == nullptr) return nullptr;
Elliott Hughes021335e2016-01-19 16:28:15 -0800119
Elliott Hughes2704bd12016-01-20 17:14:53 -0800120 glue* g = reinterpret_cast<glue*>(data);
121 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
122 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
123 g->next = NULL;
124 g->niobs = n;
125 g->iobs = p;
126 while (--n >= 0) {
127 *p = empty;
128 _FILEEXT_SETUP(p, pext);
129 p++;
130 pext++;
131 }
132 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800133}
134
Elliott Hughes80e4c152017-07-21 13:57:55 -0700135static inline void free_fgetln_buffer(FILE* fp) {
136 if (__predict_false(fp->_lb._base != nullptr)) {
137 free(fp->_lb._base);
138 fp->_lb._base = nullptr;
139 }
140}
141
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800142/*
143 * Find a free FILE for fopen et al.
144 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800145FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800146 FILE *fp;
147 int n;
148 struct glue *g;
149
Kenny Rootf5823402011-02-12 07:13:44 -0800150 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
151 for (g = &__sglue; g != NULL; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800152 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
153 if (fp->_flags == 0)
154 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800155 }
Kenny Rootf5823402011-02-12 07:13:44 -0800156
157 /* release lock while mallocing */
158 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
159 if ((g = moreglue(NDYNAMIC)) == NULL)
160 return (NULL);
161 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
162 lastglue->next = g;
163 lastglue = g;
164 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800165found:
166 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800167 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168 fp->_p = NULL; /* no current pointer */
169 fp->_w = 0; /* nothing to read or write */
170 fp->_r = 0;
171 fp->_bf._base = NULL; /* no buffer */
172 fp->_bf._size = 0;
173 fp->_lbfsize = 0; /* not line buffered */
174 fp->_file = -1; /* no file */
Elliott Hughes023c3072016-01-22 15:04:51 -0800175
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800176 fp->_lb._base = NULL; /* no line buffer */
177 fp->_lb._size = 0;
178 _FILEEXT_INIT(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800179
180 // Caller sets cookie, _read/_write etc.
181 // We explicitly clear _seek and _seek64 to prevent subtle bugs.
182 fp->_seek = nullptr;
183 _EXT(fp)->_seek64 = nullptr;
184
185 return fp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186}
187
Elliott Hughes021335e2016-01-19 16:28:15 -0800188extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800189 // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
190 _fwalk(__sflush);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800191}
Elliott Hughes923f1652016-01-19 15:46:05 -0800192
Elliott Hughes023c3072016-01-22 15:04:51 -0800193static FILE* __fopen(int fd, int flags) {
194#if !defined(__LP64__)
195 if (fd > SHRT_MAX) {
196 errno = EMFILE;
197 return nullptr;
198 }
199#endif
200
201 FILE* fp = __sfp();
202 if (fp != nullptr) {
203 fp->_file = fd;
204 fp->_flags = flags;
205 fp->_cookie = fp;
206 fp->_read = __sread;
207 fp->_write = __swrite;
208 fp->_close = __sclose;
209 _EXT(fp)->_seek64 = __sseek64;
210 }
211 return fp;
212}
213
214FILE* fopen(const char* file, const char* mode) {
215 int oflags;
216 int flags = __sflags(mode, &oflags);
217 if (flags == 0) return nullptr;
218
219 int fd = open(file, oflags, DEFFILEMODE);
220 if (fd == -1) {
221 return nullptr;
222 }
223
224 FILE* fp = __fopen(fd, flags);
225 if (fp == nullptr) {
226 ErrnoRestorer errno_restorer;
227 close(fd);
228 return nullptr;
229 }
230
231 // When opening in append mode, even though we use O_APPEND,
232 // we need to seek to the end so that ftell() gets the right
233 // answer. If the user then alters the seek pointer, or
234 // the file extends, this will fail, but there is not much
235 // we can do about this. (We could set __SAPP and check in
236 // fseek and ftell.)
237 // TODO: check in __sseek instead.
238 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
239
240 return fp;
241}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800242__strong_alias(fopen64, fopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800243
244FILE* fdopen(int fd, const char* mode) {
245 int oflags;
246 int flags = __sflags(mode, &oflags);
247 if (flags == 0) return nullptr;
248
249 // Make sure the mode the user wants is a subset of the actual mode.
250 int fdflags = fcntl(fd, F_GETFL, 0);
251 if (fdflags < 0) return nullptr;
252 int tmp = fdflags & O_ACCMODE;
253 if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
254 errno = EINVAL;
255 return nullptr;
256 }
257
258 // If opened for appending, but underlying descriptor does not have
259 // O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
260 // end before each write.
261 // TODO: use fcntl(2) to set O_APPEND instead.
262 if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) flags |= __SAPP;
263
264 // If close-on-exec was requested, then turn it on if not already.
265 if ((oflags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
266 fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
267 }
268
269 return __fopen(fd, flags);
270}
271
272// Re-direct an existing, open (probably) file to some other file.
273// ANSI is written such that the original file gets closed if at
274// all possible, no matter what.
275// TODO: rewrite this mess completely.
276FILE* freopen(const char* file, const char* mode, FILE* fp) {
277 int oflags;
278 int flags = __sflags(mode, &oflags);
279 if (flags == 0) {
280 fclose(fp);
281 return nullptr;
282 }
283
284 ScopedFileLock sfl(fp);
285
286 // There are actually programs that depend on being able to "freopen"
287 // descriptors that weren't originally open. Keep this from breaking.
288 // Remember whether the stream was open to begin with, and which file
289 // descriptor (if any) was associated with it. If it was attached to
290 // a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
291 // should work. This is unnecessary if it was not a Unix file.
292 int isopen, wantfd;
293 if (fp->_flags == 0) {
294 fp->_flags = __SEOF; // Hold on to it.
295 isopen = 0;
296 wantfd = -1;
297 } else {
298 // Flush the stream; ANSI doesn't require this.
299 if (fp->_flags & __SWR) __sflush(fp);
300
301 // If close is NULL, closing is a no-op, hence pointless.
302 isopen = fp->_close != NULL;
303 if ((wantfd = fp->_file) < 0 && isopen) {
304 (*fp->_close)(fp->_cookie);
305 isopen = 0;
306 }
307 }
308
309 // Get a new descriptor to refer to the new file.
310 int fd = open(file, oflags, DEFFILEMODE);
311 if (fd < 0 && isopen) {
312 // If out of fd's close the old one and try again.
313 if (errno == ENFILE || errno == EMFILE) {
314 (*fp->_close)(fp->_cookie);
315 isopen = 0;
316 fd = open(file, oflags, DEFFILEMODE);
317 }
318 }
319
320 int sverrno = errno;
321
322 // Finish closing fp. Even if the open succeeded above, we cannot
323 // keep fp->_base: it may be the wrong size. This loses the effect
324 // of any setbuffer calls, but stdio has always done this before.
325 if (isopen && fd != wantfd) (*fp->_close)(fp->_cookie);
326 if (fp->_flags & __SMBF) free(fp->_bf._base);
327 fp->_w = 0;
328 fp->_r = 0;
329 fp->_p = NULL;
330 fp->_bf._base = NULL;
331 fp->_bf._size = 0;
332 fp->_lbfsize = 0;
333 if (HASUB(fp)) FREEUB(fp);
334 _UB(fp)._size = 0;
335 WCIO_FREE(fp);
Elliott Hughes80e4c152017-07-21 13:57:55 -0700336 free_fgetln_buffer(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800337 fp->_lb._size = 0;
338
339 if (fd < 0) { // Did not get it after all.
340 fp->_flags = 0; // Release.
341 errno = sverrno; // Restore errno in case _close clobbered it.
342 return nullptr;
343 }
344
345 // If reopening something that was open before on a real file, try
346 // to maintain the descriptor. Various C library routines (perror)
347 // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
348 if (wantfd >= 0 && fd != wantfd) {
349 if (dup3(fd, wantfd, oflags & O_CLOEXEC) >= 0) {
350 close(fd);
351 fd = wantfd;
352 }
353 }
354
355 // _file is only a short.
356 if (fd > SHRT_MAX) {
357 fp->_flags = 0; // Release.
358 errno = EMFILE;
359 return nullptr;
360 }
361
362 fp->_flags = flags;
363 fp->_file = fd;
364 fp->_cookie = fp;
365 fp->_read = __sread;
366 fp->_write = __swrite;
367 fp->_close = __sclose;
368 _EXT(fp)->_seek64 = __sseek64;
369
370 // When opening in append mode, even though we use O_APPEND,
371 // we need to seek to the end so that ftell() gets the right
372 // answer. If the user then alters the seek pointer, or
373 // the file extends, this will fail, but there is not much
374 // we can do about this. (We could set __SAPP and check in
375 // fseek and ftell.)
376 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
377 return fp;
378}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800379__strong_alias(freopen64, freopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800380
Elliott Hughes923f1652016-01-19 15:46:05 -0800381int fclose(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800382 if (fp->_flags == 0) {
383 // Already freed!
384 errno = EBADF;
385 return EOF;
386 }
Elliott Hughes923f1652016-01-19 15:46:05 -0800387
Elliott Hughes2704bd12016-01-20 17:14:53 -0800388 ScopedFileLock sfl(fp);
389 WCIO_FREE(fp);
390 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
391 if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
392 r = EOF;
393 }
394 if (fp->_flags & __SMBF) free(fp->_bf._base);
395 if (HASUB(fp)) FREEUB(fp);
Elliott Hughes80e4c152017-07-21 13:57:55 -0700396 free_fgetln_buffer(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800397
Elliott Hughes2704bd12016-01-20 17:14:53 -0800398 // Poison this FILE so accesses after fclose will be obvious.
399 fp->_file = -1;
400 fp->_r = fp->_w = 0;
Elliott Hughes923f1652016-01-19 15:46:05 -0800401
Elliott Hughes2704bd12016-01-20 17:14:53 -0800402 // Release this FILE for reuse.
403 fp->_flags = 0;
404 return r;
Elliott Hughes923f1652016-01-19 15:46:05 -0800405}
406
Elliott Hughescceaf062016-07-29 16:31:52 -0700407int fileno_unlocked(FILE* fp) {
408 int fd = fp->_file;
409 if (fd == -1) {
410 errno = EBADF;
411 return -1;
412 }
413 return fd;
414}
415
Elliott Hughes923f1652016-01-19 15:46:05 -0800416int fileno(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800417 ScopedFileLock sfl(fp);
418 return fileno_unlocked(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800419}
Elliott Hughes021335e2016-01-19 16:28:15 -0800420
Elliott Hughescceaf062016-07-29 16:31:52 -0700421void clearerr_unlocked(FILE* fp) {
422 return __sclearerr(fp);
423}
424
425void clearerr(FILE* fp) {
426 ScopedFileLock sfl(fp);
427 clearerr_unlocked(fp);
428}
429
430int feof_unlocked(FILE* fp) {
Elliott Hughes70715da2016-08-01 16:35:17 -0700431 return ((fp->_flags & __SEOF) != 0);
Elliott Hughescceaf062016-07-29 16:31:52 -0700432}
433
434int feof(FILE* fp) {
435 ScopedFileLock sfl(fp);
436 return feof_unlocked(fp);
437}
438
439int ferror_unlocked(FILE* fp) {
440 return __sferror(fp);
441}
442
443int ferror(FILE* fp) {
444 ScopedFileLock sfl(fp);
445 return ferror_unlocked(fp);
446}
447
Elliott Hughes021335e2016-01-19 16:28:15 -0800448int __sread(void* cookie, char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800449 FILE* fp = reinterpret_cast<FILE*>(cookie);
450 return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800451}
452
453int __swrite(void* cookie, const char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800454 FILE* fp = reinterpret_cast<FILE*>(cookie);
455 if (fp->_flags & __SAPP) {
456 // The FILE* is in append mode, but the underlying fd doesn't have O_APPEND set.
457 // We need to seek manually.
Elliott Hughes023c3072016-01-22 15:04:51 -0800458 // TODO: use fcntl(2) to set O_APPEND in fdopen(3) instead?
Elliott Hughes2704bd12016-01-20 17:14:53 -0800459 TEMP_FAILURE_RETRY(lseek64(fp->_file, 0, SEEK_END));
460 }
461 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800462}
463
Elliott Hughes021335e2016-01-19 16:28:15 -0800464fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800465 FILE* fp = reinterpret_cast<FILE*>(cookie);
466 return TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
Elliott Hughes021335e2016-01-19 16:28:15 -0800467}
468
Elliott Hughes023c3072016-01-22 15:04:51 -0800469off64_t __sseek64(void* cookie, off64_t offset, int whence) {
470 FILE* fp = reinterpret_cast<FILE*>(cookie);
471 return TEMP_FAILURE_RETRY(lseek64(fp->_file, offset, whence));
472}
473
Elliott Hughes021335e2016-01-19 16:28:15 -0800474int __sclose(void* cookie) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800475 FILE* fp = reinterpret_cast<FILE*>(cookie);
476 return close(fp->_file);
477}
478
Elliott Hughes023c3072016-01-22 15:04:51 -0800479static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
480 // Use `_seek64` if set, but fall back to `_seek`.
481 if (_EXT(fp)->_seek64 != nullptr) {
482 return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence);
483 } else if (fp->_seek != nullptr) {
Elliott Hughes955426e2016-01-26 18:25:52 -0800484 off64_t result = (*fp->_seek)(fp->_cookie, offset, whence);
485#if !defined(__LP64__)
486 // Avoid sign extension if off64_t is larger than off_t.
487 if (result != -1) result &= 0xffffffff;
488#endif
489 return result;
Elliott Hughes023c3072016-01-22 15:04:51 -0800490 } else {
491 errno = ESPIPE;
492 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800493 }
Elliott Hughes2704bd12016-01-20 17:14:53 -0800494}
495
Elliott Hughes9677fab2016-01-25 15:50:59 -0800496static off64_t __ftello64_unlocked(FILE* fp) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800497 // Find offset of underlying I/O object, then adjust for buffered bytes.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800498 __sflush(fp); // May adjust seek offset on append stream.
Elliott Hughes9677fab2016-01-25 15:50:59 -0800499 off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800500 if (result == -1) {
501 return -1;
502 }
503
504 if (fp->_flags & __SRD) {
505 // Reading. Any unread characters (including
506 // those from ungetc) cause the position to be
507 // smaller than that in the underlying object.
508 result -= fp->_r;
509 if (HASUB(fp)) result -= fp->_ur;
510 } else if (fp->_flags & __SWR && fp->_p != NULL) {
511 // Writing. Any buffered characters cause the
512 // position to be greater than that in the
513 // underlying object.
514 result += fp->_p - fp->_bf._base;
515 }
516 return result;
517}
518
Elliott Hughes9677fab2016-01-25 15:50:59 -0800519int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800520 ScopedFileLock sfl(fp);
521
Elliott Hughes023c3072016-01-22 15:04:51 -0800522 // Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800523 // After this, whence is either SEEK_SET or SEEK_END.
524 if (whence == SEEK_CUR) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800525 fpos64_t current_offset = __ftello64_unlocked(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800526 if (current_offset == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800527 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800528 }
529 offset += current_offset;
530 whence = SEEK_SET;
531 } else if (whence != SEEK_SET && whence != SEEK_END) {
532 errno = EINVAL;
Elliott Hughes9677fab2016-01-25 15:50:59 -0800533 return -1;
534 }
535
536 // If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
537 if (off_t_bits == 32 && offset > LONG_MAX) {
538 errno = EOVERFLOW;
539 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800540 }
541
542 if (fp->_bf._base == NULL) __smakebuf(fp);
543
544 // Flush unwritten data and attempt the seek.
Elliott Hughes023c3072016-01-22 15:04:51 -0800545 if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800546 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800547 }
548
549 // Success: clear EOF indicator and discard ungetc() data.
550 if (HASUB(fp)) FREEUB(fp);
551 fp->_p = fp->_bf._base;
552 fp->_r = 0;
553 /* fp->_w = 0; */ /* unnecessary (I think...) */
554 fp->_flags &= ~__SEOF;
555 return 0;
556}
557
Elliott Hughes9677fab2016-01-25 15:50:59 -0800558int fseeko(FILE* fp, off_t offset, int whence) {
559 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
560 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
561}
562__strong_alias(fseek, fseeko);
563
564int fseeko64(FILE* fp, off64_t offset, int whence) {
565 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
Elliott Hughes2704bd12016-01-20 17:14:53 -0800566}
567
Elliott Hughes9677fab2016-01-25 15:50:59 -0800568int fsetpos(FILE* fp, const fpos_t* pos) {
569 return fseeko(fp, *pos, SEEK_SET);
570}
571
572int fsetpos64(FILE* fp, const fpos64_t* pos) {
573 return fseeko64(fp, *pos, SEEK_SET);
574}
575
Elliott Hughes2704bd12016-01-20 17:14:53 -0800576off_t ftello(FILE* fp) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800577 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
578 off64_t result = ftello64(fp);
579 if (result > LONG_MAX) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800580 errno = EOVERFLOW;
581 return -1;
582 }
Elliott Hughes9677fab2016-01-25 15:50:59 -0800583 return result;
584}
585__strong_alias(ftell, ftello);
586
587off64_t ftello64(FILE* fp) {
588 ScopedFileLock sfl(fp);
589 return __ftello64_unlocked(fp);
Elliott Hughes021335e2016-01-19 16:28:15 -0800590}
Elliott Hughes023c3072016-01-22 15:04:51 -0800591
Elliott Hughes023c3072016-01-22 15:04:51 -0800592int fgetpos(FILE* fp, fpos_t* pos) {
593 *pos = ftello(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800594 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800595}
596
Elliott Hughes9677fab2016-01-25 15:50:59 -0800597int fgetpos64(FILE* fp, fpos64_t* pos) {
598 *pos = ftello64(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800599 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800600}
Elliott Hughes03e65eb2016-01-26 14:13:04 -0800601
602static FILE* __funopen(const void* cookie,
603 int (*read_fn)(void*, char*, int),
604 int (*write_fn)(void*, const char*, int),
605 int (*close_fn)(void*)) {
606 if (read_fn == nullptr && write_fn == nullptr) {
607 errno = EINVAL;
608 return nullptr;
609 }
610
611 FILE* fp = __sfp();
612 if (fp == nullptr) return nullptr;
613
614 if (read_fn != nullptr && write_fn != nullptr) {
615 fp->_flags = __SRW;
616 } else if (read_fn != nullptr) {
617 fp->_flags = __SRD;
618 } else if (write_fn != nullptr) {
619 fp->_flags = __SWR;
620 }
621
622 fp->_file = -1;
623 fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
624 fp->_read = read_fn;
625 fp->_write = write_fn;
626 fp->_close = close_fn;
627
628 return fp;
629}
630
631FILE* funopen(const void* cookie,
632 int (*read_fn)(void*, char*, int),
633 int (*write_fn)(void*, const char*, int),
634 fpos_t (*seek_fn)(void*, fpos_t, int),
635 int (*close_fn)(void*)) {
636 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
637 if (fp != nullptr) {
638 fp->_seek = seek_fn;
639 }
640 return fp;
641}
642
643FILE* funopen64(const void* cookie,
644 int (*read_fn)(void*, char*, int),
645 int (*write_fn)(void*, const char*, int),
646 fpos64_t (*seek_fn)(void*, fpos64_t, int),
647 int (*close_fn)(void*)) {
648 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
649 if (fp != nullptr) {
650 _EXT(fp)->_seek64 = seek_fn;
651 }
652 return fp;
653}
Elliott Hughes20788ae2016-06-09 15:16:32 -0700654
Elliott Hughes53cf3482016-08-09 13:06:41 -0700655int asprintf(char** s, const char* fmt, ...) {
656 PRINTF_IMPL(vasprintf(s, fmt, ap));
657}
658
Elliott Hughes20788ae2016-06-09 15:16:32 -0700659char* ctermid(char* s) {
660 return s ? strcpy(s, _PATH_TTY) : const_cast<char*>(_PATH_TTY);
661}
Elliott Hughescceaf062016-07-29 16:31:52 -0700662
Elliott Hughes70715da2016-08-01 16:35:17 -0700663int dprintf(int fd, const char* fmt, ...) {
664 PRINTF_IMPL(vdprintf(fd, fmt, ap));
665}
666
667int fprintf(FILE* fp, const char* fmt, ...) {
668 PRINTF_IMPL(vfprintf(fp, fmt, ap));
669}
670
Elliott Hughescceaf062016-07-29 16:31:52 -0700671int fgetc(FILE* fp) {
672 return getc(fp);
673}
674
675int fputc(int c, FILE* fp) {
676 return putc(c, fp);
677}
678
Elliott Hughes70715da2016-08-01 16:35:17 -0700679int fscanf(FILE* fp, const char* fmt, ...) {
680 PRINTF_IMPL(vfscanf(fp, fmt, ap));
681}
682
683int fwprintf(FILE* fp, const wchar_t* fmt, ...) {
684 PRINTF_IMPL(vfwprintf(fp, fmt, ap));
685}
686
687int fwscanf(FILE* fp, const wchar_t* fmt, ...) {
688 PRINTF_IMPL(vfwscanf(fp, fmt, ap));
689}
690
691int getc(FILE* fp) {
692 ScopedFileLock sfl(fp);
693 return getc_unlocked(fp);
694}
695
696int getc_unlocked(FILE* fp) {
697 return __sgetc(fp);
698}
699
700int getchar_unlocked() {
701 return getc_unlocked(stdin);
702}
703
704int getchar() {
705 return getc(stdin);
706}
707
Elliott Hughescceaf062016-07-29 16:31:52 -0700708ssize_t getline(char** buf, size_t* len, FILE* fp) {
709 return getdelim(buf, len, '\n', fp);
710}
711
712wint_t getwc(FILE* fp) {
713 return fgetwc(fp);
714}
715
716wint_t getwchar() {
717 return fgetwc(stdin);
718}
719
Elliott Hughes70715da2016-08-01 16:35:17 -0700720int printf(const char* fmt, ...) {
721 PRINTF_IMPL(vfprintf(stdout, fmt, ap));
722}
723
724int putc(int c, FILE* fp) {
725 ScopedFileLock sfl(fp);
726 return putc_unlocked(c, fp);
727}
728
729int putc_unlocked(int c, FILE* fp) {
730 if (cantwrite(fp)) {
731 errno = EBADF;
732 return EOF;
733 }
734 _SET_ORIENTATION(fp, -1);
735 if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && c != '\n')) {
736 return (*fp->_p++ = c);
737 }
738 return (__swbuf(c, fp));
739}
740
741int putchar(int c) {
742 return putc(c, stdout);
743}
744
745int putchar_unlocked(int c) {
746 return putc_unlocked(c, stdout);
747}
748
Elliott Hughescceaf062016-07-29 16:31:52 -0700749wint_t putwc(wchar_t wc, FILE* fp) {
750 return fputwc(wc, fp);
751}
752
753wint_t putwchar(wchar_t wc) {
754 return fputwc(wc, stdout);
755}
756
Elliott Hughesd1f25a72016-08-05 15:53:03 -0700757int remove(const char* path) {
758 if (unlink(path) != -1) return 0;
759 if (errno != EISDIR) return -1;
760 return rmdir(path);
761}
762
Elliott Hughescceaf062016-07-29 16:31:52 -0700763void rewind(FILE* fp) {
764 ScopedFileLock sfl(fp);
765 fseek(fp, 0, SEEK_SET);
766 clearerr_unlocked(fp);
767}
768
Elliott Hughes70715da2016-08-01 16:35:17 -0700769int scanf(const char* fmt, ...) {
770 PRINTF_IMPL(vfscanf(stdin, fmt, ap));
771}
772
Elliott Hughescceaf062016-07-29 16:31:52 -0700773void setbuf(FILE* fp, char* buf) {
774 setbuffer(fp, buf, BUFSIZ);
775}
776
777void setbuffer(FILE* fp, char* buf, int size) {
778 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
779}
780
781int setlinebuf(FILE* fp) {
782 return setvbuf(fp, nullptr, _IOLBF, 0);
783}
784
Elliott Hughes53cf3482016-08-09 13:06:41 -0700785int snprintf(char* s, size_t n, const char* fmt, ...) {
786 PRINTF_IMPL(vsnprintf(s, n, fmt, ap));
787}
788
789int sprintf(char* s, const char* fmt, ...) {
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700790 PRINTF_IMPL(vsprintf(s, fmt, ap));
Elliott Hughes53cf3482016-08-09 13:06:41 -0700791}
792
793int sscanf(const char* s, const char* fmt, ...) {
794 PRINTF_IMPL(vsscanf(s, fmt, ap));
795}
796
Elliott Hughes70715da2016-08-01 16:35:17 -0700797int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) {
798 PRINTF_IMPL(vswprintf(s, n, fmt, ap));
799}
800
801int swscanf(const wchar_t* s, const wchar_t* fmt, ...) {
802 PRINTF_IMPL(vswscanf(s, fmt, ap));
803}
804
Elliott Hughescceaf062016-07-29 16:31:52 -0700805int vprintf(const char* fmt, va_list ap) {
806 return vfprintf(stdout, fmt, ap);
807}
808
809int vscanf(const char* fmt, va_list ap) {
810 return vfscanf(stdin, fmt, ap);
811}
812
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700813int vsnprintf(char* s, size_t n, const char* fmt, va_list ap) {
814 // stdio internals use int rather than size_t.
815 static_assert(INT_MAX <= SSIZE_MAX, "SSIZE_MAX too large to fit in int");
816
817 __check_count("vsnprintf", "size", n);
818
819 // Stdio internals do not deal correctly with zero length buffer.
820 char dummy;
821 if (n == 0) {
822 s = &dummy;
823 n = 1;
824 }
825
826 FILE f;
827 __sfileext fext;
828 _FILEEXT_SETUP(&f, &fext);
829 f._file = -1;
830 f._flags = __SWR | __SSTR;
831 f._bf._base = f._p = reinterpret_cast<unsigned char*>(s);
832 f._bf._size = f._w = n - 1;
833
834 int result = __vfprintf(&f, fmt, ap);
835 *f._p = '\0';
836 return result;
837}
838
Elliott Hughes53cf3482016-08-09 13:06:41 -0700839int vsprintf(char* s, const char* fmt, va_list ap) {
Elliott Hughesfb3873d2016-08-10 11:07:54 -0700840 return vsnprintf(s, SSIZE_MAX, fmt, ap);
Elliott Hughes53cf3482016-08-09 13:06:41 -0700841}
842
Elliott Hughescceaf062016-07-29 16:31:52 -0700843int vwprintf(const wchar_t* fmt, va_list ap) {
844 return vfwprintf(stdout, fmt, ap);
845}
846
847int vwscanf(const wchar_t* fmt, va_list ap) {
848 return vfwscanf(stdin, fmt, ap);
849}
Elliott Hughes70715da2016-08-01 16:35:17 -0700850
851int wprintf(const wchar_t* fmt, ...) {
852 PRINTF_IMPL(vfwprintf(stdout, fmt, ap));
853}
854
855int wscanf(const wchar_t* fmt, ...) {
856 PRINTF_IMPL(vfwscanf(stdin, fmt, ap));
857}
Dan Albert3037ea42016-10-06 15:46:45 -0700858
859namespace {
860
861namespace phony {
862#include <bits/struct_file.h>
863}
864
865static_assert(sizeof(::__sFILE) == sizeof(phony::__sFILE),
866 "size mismatch between `struct __sFILE` implementation and public stub");
867static_assert(alignof(::__sFILE) == alignof(phony::__sFILE),
868 "alignment mismatch between `struct __sFILE` implementation and public stub");
869
870}