blob: 3aabbe23cb89b90979e603adfe8c48928639e888 [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 Hughes023c3072016-01-22 15:04:51 -080056#define std(flags, file) \
57 {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,nullptr,__swrite, \
58 {(unsigned char *)(__sFext+file), 0},nullptr,0,{0},{0},{0,0},0,0}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080059
Kenny Rootf5823402011-02-12 07:13:44 -080060_THREAD_PRIVATE_MUTEX(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080061
Elliott Hughes29ee6392015-12-07 11:07:15 -080062// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
63#define SBUF_INIT {0,0}
64#if defined(__LP64__)
65#define MBSTATE_T_INIT {{0},{0}}
66#else
67#define MBSTATE_T_INIT {{0}}
68#endif
69#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
70
Elliott Hughesbb46afd2015-12-04 18:03:12 -080071static struct __sfileext __sFext[3] = {
Elliott Hughes023c3072016-01-22 15:04:51 -080072 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
73 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
74 { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
Elliott Hughesbb46afd2015-12-04 18:03:12 -080075};
Elliott Hughesf0141df2015-10-12 12:44:23 -070076
77// __sF is exported for backwards compatibility. Until M, we didn't have symbols
78// for stdin/stdout/stderr; they were macros accessing __sF.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080079FILE __sF[3] = {
Elliott Hughesbb46afd2015-12-04 18:03:12 -080080 std(__SRD, STDIN_FILENO),
81 std(__SWR, STDOUT_FILENO),
82 std(__SWR|__SNBF, STDERR_FILENO),
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080083};
Elliott Hughesf0141df2015-10-12 12:44:23 -070084
Elliott Hughes168667c2014-11-14 14:42:59 -080085FILE* stdin = &__sF[0];
86FILE* stdout = &__sF[1];
87FILE* stderr = &__sF[2];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088
Elliott Hughesbb46afd2015-12-04 18:03:12 -080089struct glue __sglue = { NULL, 3, __sF };
90static struct glue* lastglue = &__sglue;
91
Elliott Hughes2704bd12016-01-20 17:14:53 -080092class ScopedFileLock {
93 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -070094 explicit ScopedFileLock(FILE* fp) : fp_(fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -080095 FLOCKFILE(fp_);
96 }
97 ~ScopedFileLock() {
98 FUNLOCKFILE(fp_);
99 }
100
101 private:
102 FILE* fp_;
103};
104
Elliott Hughes021335e2016-01-19 16:28:15 -0800105static glue* moreglue(int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800106 static FILE empty;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800107
Elliott Hughes2704bd12016-01-20 17:14:53 -0800108 char* data = new char[sizeof(glue) + ALIGNBYTES + n * sizeof(FILE) + n * sizeof(__sfileext)];
109 if (data == nullptr) return nullptr;
Elliott Hughes021335e2016-01-19 16:28:15 -0800110
Elliott Hughes2704bd12016-01-20 17:14:53 -0800111 glue* g = reinterpret_cast<glue*>(data);
112 FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
113 __sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
114 g->next = NULL;
115 g->niobs = n;
116 g->iobs = p;
117 while (--n >= 0) {
118 *p = empty;
119 _FILEEXT_SETUP(p, pext);
120 p++;
121 pext++;
122 }
123 return g;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800124}
125
126/*
127 * Find a free FILE for fopen et al.
128 */
Elliott Hughes021335e2016-01-19 16:28:15 -0800129FILE* __sfp(void) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800130 FILE *fp;
131 int n;
132 struct glue *g;
133
Kenny Rootf5823402011-02-12 07:13:44 -0800134 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
135 for (g = &__sglue; g != NULL; g = g->next) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800136 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
137 if (fp->_flags == 0)
138 goto found;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139 }
Kenny Rootf5823402011-02-12 07:13:44 -0800140
141 /* release lock while mallocing */
142 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
143 if ((g = moreglue(NDYNAMIC)) == NULL)
144 return (NULL);
145 _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
146 lastglue->next = g;
147 lastglue = g;
148 fp = g->iobs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800149found:
150 fp->_flags = 1; /* reserve this slot; caller sets real flags */
Kenny Rootf5823402011-02-12 07:13:44 -0800151 _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800152 fp->_p = NULL; /* no current pointer */
153 fp->_w = 0; /* nothing to read or write */
154 fp->_r = 0;
155 fp->_bf._base = NULL; /* no buffer */
156 fp->_bf._size = 0;
157 fp->_lbfsize = 0; /* not line buffered */
158 fp->_file = -1; /* no file */
Elliott Hughes023c3072016-01-22 15:04:51 -0800159
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800160 fp->_lb._base = NULL; /* no line buffer */
161 fp->_lb._size = 0;
162 _FILEEXT_INIT(fp);
Elliott Hughes023c3072016-01-22 15:04:51 -0800163
164 // Caller sets cookie, _read/_write etc.
165 // We explicitly clear _seek and _seek64 to prevent subtle bugs.
166 fp->_seek = nullptr;
167 _EXT(fp)->_seek64 = nullptr;
168
169 return fp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800170}
171
Elliott Hughes021335e2016-01-19 16:28:15 -0800172extern "C" __LIBC_HIDDEN__ void __libc_stdio_cleanup(void) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800173 // Equivalent to fflush(nullptr), but without all the locking since we're shutting down anyway.
174 _fwalk(__sflush);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800175}
Elliott Hughes923f1652016-01-19 15:46:05 -0800176
Elliott Hughes023c3072016-01-22 15:04:51 -0800177static FILE* __fopen(int fd, int flags) {
178#if !defined(__LP64__)
179 if (fd > SHRT_MAX) {
180 errno = EMFILE;
181 return nullptr;
182 }
183#endif
184
185 FILE* fp = __sfp();
186 if (fp != nullptr) {
187 fp->_file = fd;
188 fp->_flags = flags;
189 fp->_cookie = fp;
190 fp->_read = __sread;
191 fp->_write = __swrite;
192 fp->_close = __sclose;
193 _EXT(fp)->_seek64 = __sseek64;
194 }
195 return fp;
196}
197
198FILE* fopen(const char* file, const char* mode) {
199 int oflags;
200 int flags = __sflags(mode, &oflags);
201 if (flags == 0) return nullptr;
202
203 int fd = open(file, oflags, DEFFILEMODE);
204 if (fd == -1) {
205 return nullptr;
206 }
207
208 FILE* fp = __fopen(fd, flags);
209 if (fp == nullptr) {
210 ErrnoRestorer errno_restorer;
211 close(fd);
212 return nullptr;
213 }
214
215 // When opening in append mode, even though we use O_APPEND,
216 // we need to seek to the end so that ftell() gets the right
217 // answer. If the user then alters the seek pointer, or
218 // the file extends, this will fail, but there is not much
219 // we can do about this. (We could set __SAPP and check in
220 // fseek and ftell.)
221 // TODO: check in __sseek instead.
222 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
223
224 return fp;
225}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800226__strong_alias(fopen64, fopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800227
228FILE* fdopen(int fd, const char* mode) {
229 int oflags;
230 int flags = __sflags(mode, &oflags);
231 if (flags == 0) return nullptr;
232
233 // Make sure the mode the user wants is a subset of the actual mode.
234 int fdflags = fcntl(fd, F_GETFL, 0);
235 if (fdflags < 0) return nullptr;
236 int tmp = fdflags & O_ACCMODE;
237 if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
238 errno = EINVAL;
239 return nullptr;
240 }
241
242 // If opened for appending, but underlying descriptor does not have
243 // O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
244 // end before each write.
245 // TODO: use fcntl(2) to set O_APPEND instead.
246 if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) flags |= __SAPP;
247
248 // If close-on-exec was requested, then turn it on if not already.
249 if ((oflags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
250 fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
251 }
252
253 return __fopen(fd, flags);
254}
255
256// Re-direct an existing, open (probably) file to some other file.
257// ANSI is written such that the original file gets closed if at
258// all possible, no matter what.
259// TODO: rewrite this mess completely.
260FILE* freopen(const char* file, const char* mode, FILE* fp) {
261 int oflags;
262 int flags = __sflags(mode, &oflags);
263 if (flags == 0) {
264 fclose(fp);
265 return nullptr;
266 }
267
268 ScopedFileLock sfl(fp);
269
270 // There are actually programs that depend on being able to "freopen"
271 // descriptors that weren't originally open. Keep this from breaking.
272 // Remember whether the stream was open to begin with, and which file
273 // descriptor (if any) was associated with it. If it was attached to
274 // a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
275 // should work. This is unnecessary if it was not a Unix file.
276 int isopen, wantfd;
277 if (fp->_flags == 0) {
278 fp->_flags = __SEOF; // Hold on to it.
279 isopen = 0;
280 wantfd = -1;
281 } else {
282 // Flush the stream; ANSI doesn't require this.
283 if (fp->_flags & __SWR) __sflush(fp);
284
285 // If close is NULL, closing is a no-op, hence pointless.
286 isopen = fp->_close != NULL;
287 if ((wantfd = fp->_file) < 0 && isopen) {
288 (*fp->_close)(fp->_cookie);
289 isopen = 0;
290 }
291 }
292
293 // Get a new descriptor to refer to the new file.
294 int fd = open(file, oflags, DEFFILEMODE);
295 if (fd < 0 && isopen) {
296 // If out of fd's close the old one and try again.
297 if (errno == ENFILE || errno == EMFILE) {
298 (*fp->_close)(fp->_cookie);
299 isopen = 0;
300 fd = open(file, oflags, DEFFILEMODE);
301 }
302 }
303
304 int sverrno = errno;
305
306 // Finish closing fp. Even if the open succeeded above, we cannot
307 // keep fp->_base: it may be the wrong size. This loses the effect
308 // of any setbuffer calls, but stdio has always done this before.
309 if (isopen && fd != wantfd) (*fp->_close)(fp->_cookie);
310 if (fp->_flags & __SMBF) free(fp->_bf._base);
311 fp->_w = 0;
312 fp->_r = 0;
313 fp->_p = NULL;
314 fp->_bf._base = NULL;
315 fp->_bf._size = 0;
316 fp->_lbfsize = 0;
317 if (HASUB(fp)) FREEUB(fp);
318 _UB(fp)._size = 0;
319 WCIO_FREE(fp);
320 if (HASLB(fp)) FREELB(fp);
321 fp->_lb._size = 0;
322
323 if (fd < 0) { // Did not get it after all.
324 fp->_flags = 0; // Release.
325 errno = sverrno; // Restore errno in case _close clobbered it.
326 return nullptr;
327 }
328
329 // If reopening something that was open before on a real file, try
330 // to maintain the descriptor. Various C library routines (perror)
331 // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
332 if (wantfd >= 0 && fd != wantfd) {
333 if (dup3(fd, wantfd, oflags & O_CLOEXEC) >= 0) {
334 close(fd);
335 fd = wantfd;
336 }
337 }
338
339 // _file is only a short.
340 if (fd > SHRT_MAX) {
341 fp->_flags = 0; // Release.
342 errno = EMFILE;
343 return nullptr;
344 }
345
346 fp->_flags = flags;
347 fp->_file = fd;
348 fp->_cookie = fp;
349 fp->_read = __sread;
350 fp->_write = __swrite;
351 fp->_close = __sclose;
352 _EXT(fp)->_seek64 = __sseek64;
353
354 // When opening in append mode, even though we use O_APPEND,
355 // we need to seek to the end so that ftell() gets the right
356 // answer. If the user then alters the seek pointer, or
357 // the file extends, this will fail, but there is not much
358 // we can do about this. (We could set __SAPP and check in
359 // fseek and ftell.)
360 if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
361 return fp;
362}
Elliott Hughesf226ee52016-02-03 11:24:28 -0800363__strong_alias(freopen64, freopen);
Elliott Hughes023c3072016-01-22 15:04:51 -0800364
Elliott Hughes923f1652016-01-19 15:46:05 -0800365int fclose(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800366 if (fp->_flags == 0) {
367 // Already freed!
368 errno = EBADF;
369 return EOF;
370 }
Elliott Hughes923f1652016-01-19 15:46:05 -0800371
Elliott Hughes2704bd12016-01-20 17:14:53 -0800372 ScopedFileLock sfl(fp);
373 WCIO_FREE(fp);
374 int r = fp->_flags & __SWR ? __sflush(fp) : 0;
375 if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
376 r = EOF;
377 }
378 if (fp->_flags & __SMBF) free(fp->_bf._base);
379 if (HASUB(fp)) FREEUB(fp);
380 if (HASLB(fp)) FREELB(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800381
Elliott Hughes2704bd12016-01-20 17:14:53 -0800382 // Poison this FILE so accesses after fclose will be obvious.
383 fp->_file = -1;
384 fp->_r = fp->_w = 0;
Elliott Hughes923f1652016-01-19 15:46:05 -0800385
Elliott Hughes2704bd12016-01-20 17:14:53 -0800386 // Release this FILE for reuse.
387 fp->_flags = 0;
388 return r;
Elliott Hughes923f1652016-01-19 15:46:05 -0800389}
390
391int fileno(FILE* fp) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800392 ScopedFileLock sfl(fp);
393 return fileno_unlocked(fp);
Elliott Hughes923f1652016-01-19 15:46:05 -0800394}
Elliott Hughes021335e2016-01-19 16:28:15 -0800395
Elliott Hughes021335e2016-01-19 16:28:15 -0800396int __sread(void* cookie, char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800397 FILE* fp = reinterpret_cast<FILE*>(cookie);
398 return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800399}
400
401int __swrite(void* cookie, const char* buf, int n) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800402 FILE* fp = reinterpret_cast<FILE*>(cookie);
403 if (fp->_flags & __SAPP) {
404 // The FILE* is in append mode, but the underlying fd doesn't have O_APPEND set.
405 // We need to seek manually.
Elliott Hughes023c3072016-01-22 15:04:51 -0800406 // TODO: use fcntl(2) to set O_APPEND in fdopen(3) instead?
Elliott Hughes2704bd12016-01-20 17:14:53 -0800407 TEMP_FAILURE_RETRY(lseek64(fp->_file, 0, SEEK_END));
408 }
409 return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
Elliott Hughes021335e2016-01-19 16:28:15 -0800410}
411
Elliott Hughes021335e2016-01-19 16:28:15 -0800412fpos_t __sseek(void* cookie, fpos_t offset, int whence) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800413 FILE* fp = reinterpret_cast<FILE*>(cookie);
414 return TEMP_FAILURE_RETRY(lseek(fp->_file, offset, whence));
Elliott Hughes021335e2016-01-19 16:28:15 -0800415}
416
Elliott Hughes023c3072016-01-22 15:04:51 -0800417off64_t __sseek64(void* cookie, off64_t offset, int whence) {
418 FILE* fp = reinterpret_cast<FILE*>(cookie);
419 return TEMP_FAILURE_RETRY(lseek64(fp->_file, offset, whence));
420}
421
Elliott Hughes021335e2016-01-19 16:28:15 -0800422int __sclose(void* cookie) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800423 FILE* fp = reinterpret_cast<FILE*>(cookie);
424 return close(fp->_file);
425}
426
Elliott Hughes023c3072016-01-22 15:04:51 -0800427static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
428 // Use `_seek64` if set, but fall back to `_seek`.
429 if (_EXT(fp)->_seek64 != nullptr) {
430 return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence);
431 } else if (fp->_seek != nullptr) {
Elliott Hughes955426e2016-01-26 18:25:52 -0800432 off64_t result = (*fp->_seek)(fp->_cookie, offset, whence);
433#if !defined(__LP64__)
434 // Avoid sign extension if off64_t is larger than off_t.
435 if (result != -1) result &= 0xffffffff;
436#endif
437 return result;
Elliott Hughes023c3072016-01-22 15:04:51 -0800438 } else {
439 errno = ESPIPE;
440 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800441 }
Elliott Hughes2704bd12016-01-20 17:14:53 -0800442}
443
Elliott Hughes9677fab2016-01-25 15:50:59 -0800444static off64_t __ftello64_unlocked(FILE* fp) {
Elliott Hughes023c3072016-01-22 15:04:51 -0800445 // Find offset of underlying I/O object, then adjust for buffered bytes.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800446 __sflush(fp); // May adjust seek offset on append stream.
Elliott Hughes9677fab2016-01-25 15:50:59 -0800447 off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800448 if (result == -1) {
449 return -1;
450 }
451
452 if (fp->_flags & __SRD) {
453 // Reading. Any unread characters (including
454 // those from ungetc) cause the position to be
455 // smaller than that in the underlying object.
456 result -= fp->_r;
457 if (HASUB(fp)) result -= fp->_ur;
458 } else if (fp->_flags & __SWR && fp->_p != NULL) {
459 // Writing. Any buffered characters cause the
460 // position to be greater than that in the
461 // underlying object.
462 result += fp->_p - fp->_bf._base;
463 }
464 return result;
465}
466
Elliott Hughes9677fab2016-01-25 15:50:59 -0800467int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800468 ScopedFileLock sfl(fp);
469
Elliott Hughes023c3072016-01-22 15:04:51 -0800470 // Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
Elliott Hughes2704bd12016-01-20 17:14:53 -0800471 // After this, whence is either SEEK_SET or SEEK_END.
472 if (whence == SEEK_CUR) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800473 fpos64_t current_offset = __ftello64_unlocked(fp);
Elliott Hughes2704bd12016-01-20 17:14:53 -0800474 if (current_offset == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800475 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800476 }
477 offset += current_offset;
478 whence = SEEK_SET;
479 } else if (whence != SEEK_SET && whence != SEEK_END) {
480 errno = EINVAL;
Elliott Hughes9677fab2016-01-25 15:50:59 -0800481 return -1;
482 }
483
484 // If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
485 if (off_t_bits == 32 && offset > LONG_MAX) {
486 errno = EOVERFLOW;
487 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800488 }
489
490 if (fp->_bf._base == NULL) __smakebuf(fp);
491
492 // Flush unwritten data and attempt the seek.
Elliott Hughes023c3072016-01-22 15:04:51 -0800493 if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800494 return -1;
Elliott Hughes2704bd12016-01-20 17:14:53 -0800495 }
496
497 // Success: clear EOF indicator and discard ungetc() data.
498 if (HASUB(fp)) FREEUB(fp);
499 fp->_p = fp->_bf._base;
500 fp->_r = 0;
501 /* fp->_w = 0; */ /* unnecessary (I think...) */
502 fp->_flags &= ~__SEOF;
503 return 0;
504}
505
Elliott Hughes9677fab2016-01-25 15:50:59 -0800506int fseeko(FILE* fp, off_t offset, int whence) {
507 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
508 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
509}
510__strong_alias(fseek, fseeko);
511
512int fseeko64(FILE* fp, off64_t offset, int whence) {
513 return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
Elliott Hughes2704bd12016-01-20 17:14:53 -0800514}
515
Elliott Hughes9677fab2016-01-25 15:50:59 -0800516int fsetpos(FILE* fp, const fpos_t* pos) {
517 return fseeko(fp, *pos, SEEK_SET);
518}
519
520int fsetpos64(FILE* fp, const fpos64_t* pos) {
521 return fseeko64(fp, *pos, SEEK_SET);
522}
523
Elliott Hughes2704bd12016-01-20 17:14:53 -0800524off_t ftello(FILE* fp) {
Elliott Hughes9677fab2016-01-25 15:50:59 -0800525 static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
526 off64_t result = ftello64(fp);
527 if (result > LONG_MAX) {
Elliott Hughes2704bd12016-01-20 17:14:53 -0800528 errno = EOVERFLOW;
529 return -1;
530 }
Elliott Hughes9677fab2016-01-25 15:50:59 -0800531 return result;
532}
533__strong_alias(ftell, ftello);
534
535off64_t ftello64(FILE* fp) {
536 ScopedFileLock sfl(fp);
537 return __ftello64_unlocked(fp);
Elliott Hughes021335e2016-01-19 16:28:15 -0800538}
Elliott Hughes023c3072016-01-22 15:04:51 -0800539
Elliott Hughes023c3072016-01-22 15:04:51 -0800540int fgetpos(FILE* fp, fpos_t* pos) {
541 *pos = ftello(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800542 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800543}
544
Elliott Hughes9677fab2016-01-25 15:50:59 -0800545int fgetpos64(FILE* fp, fpos64_t* pos) {
546 *pos = ftello64(fp);
Elliott Hughes955426e2016-01-26 18:25:52 -0800547 return (*pos == -1) ? -1 : 0;
Elliott Hughes023c3072016-01-22 15:04:51 -0800548}
Elliott Hughes03e65eb2016-01-26 14:13:04 -0800549
550static FILE* __funopen(const void* cookie,
551 int (*read_fn)(void*, char*, int),
552 int (*write_fn)(void*, const char*, int),
553 int (*close_fn)(void*)) {
554 if (read_fn == nullptr && write_fn == nullptr) {
555 errno = EINVAL;
556 return nullptr;
557 }
558
559 FILE* fp = __sfp();
560 if (fp == nullptr) return nullptr;
561
562 if (read_fn != nullptr && write_fn != nullptr) {
563 fp->_flags = __SRW;
564 } else if (read_fn != nullptr) {
565 fp->_flags = __SRD;
566 } else if (write_fn != nullptr) {
567 fp->_flags = __SWR;
568 }
569
570 fp->_file = -1;
571 fp->_cookie = const_cast<void*>(cookie); // The funopen(3) API is incoherent.
572 fp->_read = read_fn;
573 fp->_write = write_fn;
574 fp->_close = close_fn;
575
576 return fp;
577}
578
579FILE* funopen(const void* cookie,
580 int (*read_fn)(void*, char*, int),
581 int (*write_fn)(void*, const char*, int),
582 fpos_t (*seek_fn)(void*, fpos_t, int),
583 int (*close_fn)(void*)) {
584 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
585 if (fp != nullptr) {
586 fp->_seek = seek_fn;
587 }
588 return fp;
589}
590
591FILE* funopen64(const void* cookie,
592 int (*read_fn)(void*, char*, int),
593 int (*write_fn)(void*, const char*, int),
594 fpos64_t (*seek_fn)(void*, fpos64_t, int),
595 int (*close_fn)(void*)) {
596 FILE* fp = __funopen(cookie, read_fn, write_fn, close_fn);
597 if (fp != nullptr) {
598 _EXT(fp)->_seek64 = seek_fn;
599 }
600 return fp;
601}
Elliott Hughes20788ae2016-06-09 15:16:32 -0700602
603char* ctermid(char* s) {
604 return s ? strcpy(s, _PATH_TTY) : const_cast<char*>(_PATH_TTY);
605}