blob: 53b3faeb164be39f53ab943cd4b8daa6f3f259be [file] [log] [blame]
Dmitriy Ivanov623b0d02014-05-14 23:11:05 -07001/* $OpenBSD: findfp.c,v 1.15 2013/12/17 16:33:27 deraadt Exp $ */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002/*-
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Chris Torek.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <stdio.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080035
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080036#include <errno.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080037#include <fcntl.h>
Elliott Hughes2704bd12016-01-20 17:14:53 -080038#include <limits.h>
Elliott Hughes20788ae2016-06-09 15:16:32 -070039#include <paths.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040#include <stdlib.h>
41#include <string.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080042#include <sys/param.h>
Elliott Hughes023c3072016-01-22 15:04:51 -080043#include <sys/stat.h>
Elliott Hughes021335e2016-01-19 16:28:15 -080044#include <unistd.h>
45
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080046#include "local.h"
47#include "glue.h"
Elliott Hughes023c3072016-01-22 15:04:51 -080048#include "private/ErrnoRestorer.h"
Elliott Hughes6a03abc2014-11-03 12:32:17 -080049#include "private/thread_private.h"
50
51#define ALIGNBYTES (sizeof(uintptr_t) - 1)
52#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
Calin Juravlec20de902014-03-20 15:21:32 +000053
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080054#define NDYNAMIC 10 /* add ten more whenever necessary */
55
Elliott Hughes70715da2016-08-01 16:35:17 -070056#define PRINTF_IMPL(expr) \
57 va_list ap; \
58 va_start(ap, fmt); \
59 int result = (expr); \
60 va_end(ap); \
61 return result;
62
Elliott Hughes023c3072016-01-22 15:04:51 -080063#define std(flags, file) \
64 {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,nullptr,__swrite, \
65 {(unsigned char *)(__sFext+file), 0},nullptr,0,{0},{0},{0,0},0,0}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080066
Kenny Rootf5823402011-02-12 07:13:44 -080067_THREAD_PRIVATE_MUTEX(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080068
Elliott Hughes29ee6392015-12-07 11:07:15 -080069// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
70#define SBUF_INIT {0,0}
71#if defined(__LP64__)
72#define MBSTATE_T_INIT {{0},{0}}
73#else
74#define MBSTATE_T_INIT {{0}}
75#endif
76#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
77
Elliott Hughesbb46afd2015-12-04 18:03:12 -080078static struct __sfileext __sFext[3] = {
Elliott Hughes023c3072016-01-22 15:04:51 -080079 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
80 { 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 },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080082};
Elliott Hughesf0141df2015-10-12 12:44:23 -070083
84// __sF is exported for backwards compatibility. Until M, we didn't have symbols
85// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080086FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080087 std(__SRD, STDIN_FILENO),
88 std(__SWR, STDOUT_FILENO),
89 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080090};
Elliott Hughesf0141df2015-10-12 12:44:23 -070091
Elliott Hughes168667c2014-11-14 14:42:59 -080092FILE* stdin = &__sF[0];
93FILE* stdout = &__sF[1];
94FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080095
Elliott Hughesbb46afd2015-12-04 18:03:12 -080096struct glue __sglue = { NULL, 3, __sF };
97static struct glue* lastglue = &__sglue;
98
Elliott Hughes2704bd12016-01-20 17:14:53 -080099class ScopedFileLock {
100 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -0700101 explicit ScopedFileLock(FILE* fp) : fp_(fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800102 FLOCKFILE(fp_);
103 }
104 ~ScopedFileLock() {
105 FUNLOCKFILE(fp_);
106 }
107
108 private:
109 FILE* fp_;
110};
111
Elliott Hughes021335e2016-01-19 16:28:15 -0800112static glue* moreglue(int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800113 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800114
Elliott Hughes2704bd12016-01-20 17:14:53 -0800115 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
116 if (data == nullptr) return nullptr;
Elliott Hughes021335e2016-01-19 16:28:15 -0800117
Elliott Hughes2704bd12016-01-20 17:14:53 -0800118 glue* g = reinterpret_cast<glue*>(data);
119 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
120 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
121 g->next = NULL;
122 g->niobs = n;
123 g->iobs = p;
124 while (--n >= 0) {
125 *p = empty;
126 _FILEEXT_SETUP(p, pext);
127 p++;
128 pext++;
129 }
130 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800131}
132
133/*
134 * Find a free FILE for fopen et al.
135 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800136FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800137 FILE *fp;
138 int n;
139 struct glue *g;
140
Kenny Rootf5823402011-02-12 07:13:44 -0800141 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
142 for (g = &__sglue; g != NULL; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800143 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
144 if (fp->_flags == 0)
145 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800146 }
Kenny Rootf5823402011-02-12 07:13:44 -0800147
148 /* release lock while mallocing */
149 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
150 if ((g = moreglue(NDYNAMIC)) == NULL)
151 return (NULL);
152 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
153 lastglue->next = g;
154 lastglue = g;
155 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800156found:
157 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800158 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800159 fp->_p = NULL; /* no current pointer */
160 fp->_w = 0; /* nothing to read or write */
161 fp->_r = 0;
162 fp->_bf._base = NULL; /* no buffer */
163 fp->_bf._size = 0;
164 fp->_lbfsize = 0; /* not line buffered */
165 fp->_file = -1; /* no file */
Elliott Hughes023c3072016-01-22 15:04:51 -0800166
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800167 fp->_lb._base = NULL; /* no line buffer */
168 fp->_lb._size = 0;
169 _FILEEXT_INIT(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800170
171 // Caller sets cookie, _read/_write etc.
172 // We explicitly clear _seek and _seek64 to prevent subtle bugs.
173 fp->_seek = nullptr;
174 _EXT(fp)->_seek64 = nullptr;
175
176 return fp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800177}
178
Elliott Hughes021335e2016-01-19 16:28:15 -0800179extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800180 // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
181 _fwalk(__sflush);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800182}
Elliott Hughes923f1652016-01-19 15:46:05 -0800183
Elliott Hughes023c3072016-01-22 15:04:51 -0800184static FILE* __fopen(int fd, int flags) {
185#if !defined(__LP64__)
186 if (fd > SHRT_MAX) {
187 errno = EMFILE;
188 return nullptr;
189 }
190#endif
191
192 FILE* fp = __sfp();
193 if (fp != nullptr) {
194 fp->_file = fd;
195 fp->_flags = flags;
196 fp->_cookie = fp;
197 fp->_read = __sread;
198 fp->_write = __swrite;
199 fp->_close = __sclose;
200 _EXT(fp)->_seek64 = __sseek64;
201 }
202 return fp;
203}
204
205FILE* fopen(const char* file, const char* mode) {
206 int oflags;
207 int flags = __sflags(mode, &oflags);
208 if (flags == 0) return nullptr;
209
210 int fd = open(file, oflags, DEFFILEMODE);
211 if (fd == -1) {
212 return nullptr;
213 }
214
215 FILE* fp = __fopen(fd, flags);
216 if (fp == nullptr) {
217 ErrnoRestorer errno_restorer;
218 close(fd);
219 return nullptr;
220 }
221
222 // When opening in append mode, even though we use O_APPEND,
223 // we need to seek to the end so that ftell() gets the right
224 // answer. If the user then alters the seek pointer, or
225 // the file extends, this will fail, but there is not much
226 // we can do about this. (We could set __SAPP and check in
227 // fseek and ftell.)
228 // TODO: check in __sseek instead.
229 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
230
231 return fp;
232}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800233__strong_alias(fopen64, fopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800234
235FILE* fdopen(int fd, const char* mode) {
236 int oflags;
237 int flags = __sflags(mode, &oflags);
238 if (flags == 0) return nullptr;
239
240 // Make sure the mode the user wants is a subset of the actual mode.
241 int fdflags = fcntl(fd, F_GETFL, 0);
242 if (fdflags < 0) return nullptr;
243 int tmp = fdflags & O_ACCMODE;
244 if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
245 errno = EINVAL;
246 return nullptr;
247 }
248
249 // If opened for appending, but underlying descriptor does not have
250 // O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
251 // end before each write.
252 // TODO: use fcntl(2) to set O_APPEND instead.
253 if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) flags |= __SAPP;
254
255 // If close-on-exec was requested, then turn it on if not already.
256 if ((oflags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
257 fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
258 }
259
260 return __fopen(fd, flags);
261}
262
263// Re-direct an existing, open (probably) file to some other file.
264// ANSI is written such that the original file gets closed if at
265// all possible, no matter what.
266// TODO: rewrite this mess completely.
267FILE* freopen(const char* file, const char* mode, FILE* fp) {
268 int oflags;
269 int flags = __sflags(mode, &oflags);
270 if (flags == 0) {
271 fclose(fp);
272 return nullptr;
273 }
274
275 ScopedFileLock sfl(fp);
276
277 // There are actually programs that depend on being able to "freopen"
278 // descriptors that weren't originally open. Keep this from breaking.
279 // Remember whether the stream was open to begin with, and which file
280 // descriptor (if any) was associated with it. If it was attached to
281 // a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
282 // should work. This is unnecessary if it was not a Unix file.
283 int isopen, wantfd;
284 if (fp->_flags == 0) {
285 fp->_flags = __SEOF; // Hold on to it.
286 isopen = 0;
287 wantfd = -1;
288 } else {
289 // Flush the stream; ANSI doesn't require this.
290 if (fp->_flags & __SWR) __sflush(fp);
291
292 // If close is NULL, closing is a no-op, hence pointless.
293 isopen = fp->_close != NULL;
294 if ((wantfd = fp->_file) < 0 && isopen) {
295 (*fp->_close)(fp->_cookie);
296 isopen = 0;
297 }
298 }
299
300 // Get a new descriptor to refer to the new file.
301 int fd = open(file, oflags, DEFFILEMODE);
302 if (fd < 0 && isopen) {
303 // If out of fd's close the old one and try again.
304 if (errno == ENFILE || errno == EMFILE) {
305 (*fp->_close)(fp->_cookie);
306 isopen = 0;
307 fd = open(file, oflags, DEFFILEMODE);
308 }
309 }
310
311 int sverrno = errno;
312
313 // Finish closing fp. Even if the open succeeded above, we cannot
314 // keep fp->_base: it may be the wrong size. This loses the effect
315 // of any setbuffer calls, but stdio has always done this before.
316 if (isopen && fd != wantfd) (*fp->_close)(fp->_cookie);
317 if (fp->_flags & __SMBF) free(fp->_bf._base);
318 fp->_w = 0;
319 fp->_r = 0;
320 fp->_p = NULL;
321 fp->_bf._base = NULL;
322 fp->_bf._size = 0;
323 fp->_lbfsize = 0;
324 if (HASUB(fp)) FREEUB(fp);
325 _UB(fp)._size = 0;
326 WCIO_FREE(fp);
327 if (HASLB(fp)) FREELB(fp);
328 fp->_lb._size = 0;
329
330 if (fd < 0) { // Did not get it after all.
331 fp->_flags = 0; // Release.
332 errno = sverrno; // Restore errno in case _close clobbered it.
333 return nullptr;
334 }
335
336 // If reopening something that was open before on a real file, try
337 // to maintain the descriptor. Various C library routines (perror)
338 // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
339 if (wantfd >= 0 && fd != wantfd) {
340 if (dup3(fd, wantfd, oflags & O_CLOEXEC) >= 0) {
341 close(fd);
342 fd = wantfd;
343 }
344 }
345
346 // _file is only a short.
347 if (fd > SHRT_MAX) {
348 fp->_flags = 0; // Release.
349 errno = EMFILE;
350 return nullptr;
351 }
352
353 fp->_flags = flags;
354 fp->_file = fd;
355 fp->_cookie = fp;
356 fp->_read = __sread;
357 fp->_write = __swrite;
358 fp->_close = __sclose;
359 _EXT(fp)->_seek64 = __sseek64;
360
361 // When opening in append mode, even though we use O_APPEND,
362 // we need to seek to the end so that ftell() gets the right
363 // answer. If the user then alters the seek pointer, or
364 // the file extends, this will fail, but there is not much
365 // we can do about this. (We could set __SAPP and check in
366 // fseek and ftell.)
367 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
368 return fp;
369}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800370__strong_alias(freopen64, freopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800371
Elliott Hughes923f1652016-01-19 15:46:05 -0800372int fclose(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800373 if (fp->_flags == 0) {
374 // Already freed!
375 errno = EBADF;
376 return EOF;
377 }
Elliott Hughes923f1652016-01-19 15:46:05 -0800378
Elliott Hughes2704bd12016-01-20 17:14:53 -0800379 ScopedFileLock sfl(fp);
380 WCIO_FREE(fp);
381 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
382 if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
383 r = EOF;
384 }
385 if (fp->_flags & __SMBF) free(fp->_bf._base);
386 if (HASUB(fp)) FREEUB(fp);
387 if (HASLB(fp)) FREELB(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800388
Elliott Hughes2704bd12016-01-20 17:14:53 -0800389 // Poison this FILE so accesses after fclose will be obvious.
390 fp->_file = -1;
391 fp->_r = fp->_w = 0;
Elliott Hughes923f1652016-01-19 15:46:05 -0800392
Elliott Hughes2704bd12016-01-20 17:14:53 -0800393 // Release this FILE for reuse.
394 fp->_flags = 0;
395 return r;
Elliott Hughes923f1652016-01-19 15:46:05 -0800396}
397
Elliott Hughescceaf062016-07-29 16:31:52 -0700398int fileno_unlocked(FILE* fp) {
399 int fd = fp->_file;
400 if (fd == -1) {
401 errno = EBADF;
402 return -1;
403 }
404 return fd;
405}
406
Elliott Hughes923f1652016-01-19 15:46:05 -0800407int fileno(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800408 ScopedFileLock sfl(fp);
409 return fileno_unlocked(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800410}
Elliott Hughes021335e2016-01-19 16:28:15 -0800411
Elliott Hughescceaf062016-07-29 16:31:52 -0700412void clearerr_unlocked(FILE* fp) {
413 return __sclearerr(fp);
414}
415
416void clearerr(FILE* fp) {
417 ScopedFileLock sfl(fp);
418 clearerr_unlocked(fp);
419}
420
421int feof_unlocked(FILE* fp) {
Elliott Hughes70715da2016-08-01 16:35:17 -0700422 return ((fp->_flags & __SEOF) != 0);
Elliott Hughescceaf062016-07-29 16:31:52 -0700423}
424
425int feof(FILE* fp) {
426 ScopedFileLock sfl(fp);
427 return feof_unlocked(fp);
428}
429
430int ferror_unlocked(FILE* fp) {
431 return __sferror(fp);
432}
433
434int ferror(FILE* fp) {
435 ScopedFileLock sfl(fp);
436 return ferror_unlocked(fp);
437}
438
Elliott Hughes021335e2016-01-19 16:28:15 -0800439int __sread(void* cookie, char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800440 FILE* fp = reinterpret_cast<FILE*>(cookie);
441 return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800442}
443
444int __swrite(void* cookie, const char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800445 FILE* fp = reinterpret_cast<FILE*>(cookie);
446 if (fp->_flags & __SAPP) {
447 // The FILE* is in append mode, but the underlying fd doesn't have O_APPEND set.
448 // We need to seek manually.
Elliott Hughes023c3072016-01-22 15:04:51 -0800449 // TODO: use fcntl(2) to set O_APPEND in fdopen(3) instead?
Elliott Hughes2704bd12016-01-20 17:14:53 -0800450 TEMP_FAILURE_RETRY(lseek64(fp->_file, 0, SEEK_END));
451 }
452 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800453}
454
Elliott Hughes021335e2016-01-19 16:28:15 -0800455fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800456 FILE* fp = reinterpret_cast<FILE*>(cookie);
457 return TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
Elliott Hughes021335e2016-01-19 16:28:15 -0800458}
459
Elliott Hughes023c3072016-01-22 15:04:51 -0800460off64_t __sseek64(void* cookie, off64_t offset, int whence) {
461 FILE* fp = reinterpret_cast<FILE*>(cookie);
462 return TEMP_FAILURE_RETRY(lseek64(fp->_file, offset, whence));
463}
464
Elliott Hughes021335e2016-01-19 16:28:15 -0800465int __sclose(void* cookie) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800466 FILE* fp = reinterpret_cast<FILE*>(cookie);
467 return close(fp->_file);
468}
469
Elliott Hughes023c3072016-01-22 15:04:51 -0800470static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
471 // Use `_seek64` if set, but fall back to `_seek`.
472 if (_EXT(fp)->_seek64 != nullptr) {
473 return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence);
474 } else if (fp->_seek != nullptr) {
Elliott Hughes955426e2016-01-26 18:25:52 -0800475 off64_t result = (*fp->_seek)(fp->_cookie, offset, whence);
476#if !defined(__LP64__)
477 // Avoid sign extension if off64_t is larger than off_t.
478 if (result != -1) result &= 0xffffffff;
479#endif
480 return result;
Elliott Hughes023c3072016-01-22 15:04:51 -0800481 } else {
482 errno = ESPIPE;
483 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800484 }
Elliott Hughes2704bd12016-01-20 17:14:53 -0800485}
486
Elliott Hughes9677fab2016-01-25 15:50:59 -0800487static off64_t __ftello64_unlocked(FILE* fp) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800488 // Find offset of underlying I/O object, then adjust for buffered bytes.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800489 __sflush(fp); // May adjust seek offset on append stream.
Elliott Hughes9677fab2016-01-25 15:50:59 -0800490 off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800491 if (result == -1) {
492 return -1;
493 }
494
495 if (fp->_flags & __SRD) {
496 // Reading. Any unread characters (including
497 // those from ungetc) cause the position to be
498 // smaller than that in the underlying object.
499 result -= fp->_r;
500 if (HASUB(fp)) result -= fp->_ur;
501 } else if (fp->_flags & __SWR && fp->_p != NULL) {
502 // Writing. Any buffered characters cause the
503 // position to be greater than that in the
504 // underlying object.
505 result += fp->_p - fp->_bf._base;
506 }
507 return result;
508}
509
Elliott Hughes9677fab2016-01-25 15:50:59 -0800510int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800511 ScopedFileLock sfl(fp);
512
Elliott Hughes023c3072016-01-22 15:04:51 -0800513 // Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800514 // After this, whence is either SEEK_SET or SEEK_END.
515 if (whence == SEEK_CUR) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800516 fpos64_t current_offset = __ftello64_unlocked(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800517 if (current_offset == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800518 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800519 }
520 offset += current_offset;
521 whence = SEEK_SET;
522 } else if (whence != SEEK_SET && whence != SEEK_END) {
523 errno = EINVAL;
Elliott Hughes9677fab2016-01-25 15:50:59 -0800524 return -1;
525 }
526
527 // If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
528 if (off_t_bits == 32 && offset > LONG_MAX) {
529 errno = EOVERFLOW;
530 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800531 }
532
533 if (fp->_bf._base == NULL) __smakebuf(fp);
534
535 // Flush unwritten data and attempt the seek.
Elliott Hughes023c3072016-01-22 15:04:51 -0800536 if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800537 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800538 }
539
540 // Success: clear EOF indicator and discard ungetc() data.
541 if (HASUB(fp)) FREEUB(fp);
542 fp->_p = fp->_bf._base;
543 fp->_r = 0;
544 /* fp->_w = 0; */ /* unnecessary (I think...) */
545 fp->_flags &= ~__SEOF;
546 return 0;
547}
548
Elliott Hughes9677fab2016-01-25 15:50:59 -0800549int fseeko(FILE* fp, off_t offset, int whence) {
550 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
551 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
552}
553__strong_alias(fseek, fseeko);
554
555int fseeko64(FILE* fp, off64_t offset, int whence) {
556 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
Elliott Hughes2704bd12016-01-20 17:14:53 -0800557}
558
Elliott Hughes9677fab2016-01-25 15:50:59 -0800559int fsetpos(FILE* fp, const fpos_t* pos) {
560 return fseeko(fp, *pos, SEEK_SET);
561}
562
563int fsetpos64(FILE* fp, const fpos64_t* pos) {
564 return fseeko64(fp, *pos, SEEK_SET);
565}
566
Elliott Hughes2704bd12016-01-20 17:14:53 -0800567off_t ftello(FILE* fp) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800568 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
569 off64_t result = ftello64(fp);
570 if (result > LONG_MAX) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800571 errno = EOVERFLOW;
572 return -1;
573 }
Elliott Hughes9677fab2016-01-25 15:50:59 -0800574 return result;
575}
576__strong_alias(ftell, ftello);
577
578off64_t ftello64(FILE* fp) {
579 ScopedFileLock sfl(fp);
580 return __ftello64_unlocked(fp);
Elliott Hughes021335e2016-01-19 16:28:15 -0800581}
Elliott Hughes023c3072016-01-22 15:04:51 -0800582
Elliott Hughes023c3072016-01-22 15:04:51 -0800583int fgetpos(FILE* fp, fpos_t* pos) {
584 *pos = ftello(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800585 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800586}
587
Elliott Hughes9677fab2016-01-25 15:50:59 -0800588int fgetpos64(FILE* fp, fpos64_t* pos) {
589 *pos = ftello64(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800590 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800591}
Elliott Hughes03e65eb2016-01-26 14:13:04 -0800592
593static FILE* __funopen(const void* cookie,
594 int (*read_fn)(void*, char*, int),
595 int (*write_fn)(void*, const char*, int),
596 int (*close_fn)(void*)) {
597 if (read_fn == nullptr && write_fn == nullptr) {
598 errno = EINVAL;
599 return nullptr;
600 }
601
602 FILE* fp = __sfp();
603 if (fp == nullptr) return nullptr;
604
605 if (read_fn != nullptr && write_fn != nullptr) {
606 fp->_flags = __SRW;
607 } else if (read_fn != nullptr) {
608 fp->_flags = __SRD;
609 } else if (write_fn != nullptr) {
610 fp->_flags = __SWR;
611 }
612
613 fp->_file = -1;
614 fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
615 fp->_read = read_fn;
616 fp->_write = write_fn;
617 fp->_close = close_fn;
618
619 return fp;
620}
621
622FILE* funopen(const void* cookie,
623 int (*read_fn)(void*, char*, int),
624 int (*write_fn)(void*, const char*, int),
625 fpos_t (*seek_fn)(void*, fpos_t, int),
626 int (*close_fn)(void*)) {
627 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
628 if (fp != nullptr) {
629 fp->_seek = seek_fn;
630 }
631 return fp;
632}
633
634FILE* funopen64(const void* cookie,
635 int (*read_fn)(void*, char*, int),
636 int (*write_fn)(void*, const char*, int),
637 fpos64_t (*seek_fn)(void*, fpos64_t, int),
638 int (*close_fn)(void*)) {
639 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
640 if (fp != nullptr) {
641 _EXT(fp)->_seek64 = seek_fn;
642 }
643 return fp;
644}
Elliott Hughes20788ae2016-06-09 15:16:32 -0700645
646char* ctermid(char* s) {
647 return s ? strcpy(s, _PATH_TTY) : const_cast<char*>(_PATH_TTY);
648}
Elliott Hughescceaf062016-07-29 16:31:52 -0700649
Elliott Hughes70715da2016-08-01 16:35:17 -0700650int dprintf(int fd, const char* fmt, ...) {
651 PRINTF_IMPL(vdprintf(fd, fmt, ap));
652}
653
654int fprintf(FILE* fp, const char* fmt, ...) {
655 PRINTF_IMPL(vfprintf(fp, fmt, ap));
656}
657
Elliott Hughescceaf062016-07-29 16:31:52 -0700658int fgetc(FILE* fp) {
659 return getc(fp);
660}
661
662int fputc(int c, FILE* fp) {
663 return putc(c, fp);
664}
665
Elliott Hughes70715da2016-08-01 16:35:17 -0700666int fscanf(FILE* fp, const char* fmt, ...) {
667 PRINTF_IMPL(vfscanf(fp, fmt, ap));
668}
669
670int fwprintf(FILE* fp, const wchar_t* fmt, ...) {
671 PRINTF_IMPL(vfwprintf(fp, fmt, ap));
672}
673
674int fwscanf(FILE* fp, const wchar_t* fmt, ...) {
675 PRINTF_IMPL(vfwscanf(fp, fmt, ap));
676}
677
678int getc(FILE* fp) {
679 ScopedFileLock sfl(fp);
680 return getc_unlocked(fp);
681}
682
683int getc_unlocked(FILE* fp) {
684 return __sgetc(fp);
685}
686
687int getchar_unlocked() {
688 return getc_unlocked(stdin);
689}
690
691int getchar() {
692 return getc(stdin);
693}
694
Elliott Hughescceaf062016-07-29 16:31:52 -0700695ssize_t getline(char** buf, size_t* len, FILE* fp) {
696 return getdelim(buf, len, '\n', fp);
697}
698
699wint_t getwc(FILE* fp) {
700 return fgetwc(fp);
701}
702
703wint_t getwchar() {
704 return fgetwc(stdin);
705}
706
Elliott Hughes70715da2016-08-01 16:35:17 -0700707int printf(const char* fmt, ...) {
708 PRINTF_IMPL(vfprintf(stdout, fmt, ap));
709}
710
711int putc(int c, FILE* fp) {
712 ScopedFileLock sfl(fp);
713 return putc_unlocked(c, fp);
714}
715
716int putc_unlocked(int c, FILE* fp) {
717 if (cantwrite(fp)) {
718 errno = EBADF;
719 return EOF;
720 }
721 _SET_ORIENTATION(fp, -1);
722 if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && c != '\n')) {
723 return (*fp->_p++ = c);
724 }
725 return (__swbuf(c, fp));
726}
727
728int putchar(int c) {
729 return putc(c, stdout);
730}
731
732int putchar_unlocked(int c) {
733 return putc_unlocked(c, stdout);
734}
735
Elliott Hughescceaf062016-07-29 16:31:52 -0700736wint_t putwc(wchar_t wc, FILE* fp) {
737 return fputwc(wc, fp);
738}
739
740wint_t putwchar(wchar_t wc) {
741 return fputwc(wc, stdout);
742}
743
744void rewind(FILE* fp) {
745 ScopedFileLock sfl(fp);
746 fseek(fp, 0, SEEK_SET);
747 clearerr_unlocked(fp);
748}
749
Elliott Hughes70715da2016-08-01 16:35:17 -0700750int scanf(const char* fmt, ...) {
751 PRINTF_IMPL(vfscanf(stdin, fmt, ap));
752}
753
Elliott Hughescceaf062016-07-29 16:31:52 -0700754void setbuf(FILE* fp, char* buf) {
755 setbuffer(fp, buf, BUFSIZ);
756}
757
758void setbuffer(FILE* fp, char* buf, int size) {
759 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
760}
761
762int setlinebuf(FILE* fp) {
763 return setvbuf(fp, nullptr, _IOLBF, 0);
764}
765
Elliott Hughes70715da2016-08-01 16:35:17 -0700766int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) {
767 PRINTF_IMPL(vswprintf(s, n, fmt, ap));
768}
769
770int swscanf(const wchar_t* s, const wchar_t* fmt, ...) {
771 PRINTF_IMPL(vswscanf(s, fmt, ap));
772}
773
Elliott Hughescceaf062016-07-29 16:31:52 -0700774int vprintf(const char* fmt, va_list ap) {
775 return vfprintf(stdout, fmt, ap);
776}
777
778int vscanf(const char* fmt, va_list ap) {
779 return vfscanf(stdin, fmt, ap);
780}
781
782int vwprintf(const wchar_t* fmt, va_list ap) {
783 return vfwprintf(stdout, fmt, ap);
784}
785
786int vwscanf(const wchar_t* fmt, va_list ap) {
787 return vfwscanf(stdin, fmt, ap);
788}
Elliott Hughes70715da2016-08-01 16:35:17 -0700789
790int wprintf(const wchar_t* fmt, ...) {
791 PRINTF_IMPL(vfwprintf(stdout, fmt, ap));
792}
793
794int wscanf(const wchar_t* fmt, ...) {
795 PRINTF_IMPL(vfwscanf(stdin, fmt, ap));
796}