int fclose(FILE *fp) { int r; if (fp->_flags == 0) { /* not open! */ errno = EBADF; return (EOF); } FLOCKFILE(fp); WCIO_FREE(fp); r = fp->_flags & __SWR ? __sflush(fp) : 0; if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) r = EOF; if (fp->_flags & __SMBF) free((char *)fp->_bf._base); if (HASUB(fp)) FREEUB(fp); if (HASLB(fp)) FREELB(fp); fp->_r = fp->_w = 0; /* Mess up if reaccessed. */ fp->_flags = 0; /* Release this FILE for reuse. */ FUNLOCKFILE(fp); return (r); }
int fclose(FILE *fp) { int r; if (fp->_flags == 0) /* not open! */ { errno = EBADF; return (EOF); } FLOCKFILE(fp); r = fp->_flags & __SWR ? __sflush(fp) : 0; if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) r = EOF; if (fp->_flags & __SMBF) FREE((char *)fp->_bf._base); if (HASUB(fp)) FREEUB(fp); if (HASLB(fp)) FREELB(fp); fp->_file = -1; fp->_r = fp->_w = 0; /* Mess up if reaccessed. */ fp->_flags = 0; /* Release this FILE for reuse. */ osal_mutex_delete(fp->_extra->fl_mutex); FUNLOCKFILE(fp); return (r); }
/* * Various output routines call wsetup to be sure it is safe to write, * because either _flags does not include __SWR, or _buf is NULL. * _wsetup returns 0 if OK to write, nonzero otherwise. */ int __swsetup(FILE *fp) { /* make sure stdio is set up */ if (!__sdidinit) __sinit(); /* * If we are not writing, we had better be reading and writing. */ if ((fp->_flags & __SWR) == 0) { if ((fp->_flags & __SRW) == 0) return (EOF); if (fp->_flags & __SRD) { /* clobber any ungetc data */ if (HASUB(fp)) FREEUB(fp); fp->_flags &= ~(__SRD|__SEOF); fp->_r = 0; fp->_p = fp->_bf._base; } fp->_flags |= __SWR; } /* * Make a buffer if necessary, then set _w. */ if (fp->_bf._base == NULL) { if ((fp->_flags & (__SSTR | __SALC)) == __SSTR) return (EOF); __smakebuf(fp); } if (fp->_flags & __SLBF) { /* * It is line buffered, so make _lbfsize be -_bufsize * for the putc() macro. We will change _lbfsize back * to 0 whenever we turn off __SWR. */ fp->_w = 0; fp->_lbfsize = -fp->_bf._size; } else fp->_w = fp->_flags & __SNBF ? 0 : fp->_bf._size; return (0); }
/* * fpurge: like fflush, but without writing anything: leave the * given FILE's buffer empty. */ int fpurge(FILE *fp) { FLOCKFILE(fp); if (!fp->_flags) { FUNLOCKFILE(fp); errno = EBADF; return(EOF); } if (HASUB(fp)) FREEUB(fp); WCIO_FREE(fp); fp->_p = fp->_bf._base; fp->_r = 0; fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size; FUNLOCKFILE(fp); return (0); }
fpos_t _sseek(FILE *fp, fpos_t offset, int whence) { fpos_t ret; int serrno, errret; serrno = errno; errno = 0; ret = (*fp->_seek)(fp->_cookie, offset, whence); errret = errno; if (errno == 0) errno = serrno; /* * Disallow negative seeks per POSIX. * It is needed here to help upper level caller * in the cases it can't detect. */ if (ret < 0) { if (errret == 0) { if (offset != 0 || whence != SEEK_CUR) { if (HASUB(fp)) FREEUB(fp); fp->_p = fp->_bf._base; fp->_r = 0; fp->_flags &= ~__SEOF; } fp->_flags |= __SERR; errno = EINVAL; } else if (errret == ESPIPE) fp->_flags &= ~__SAPP; fp->_flags &= ~__SOFF; ret = -1; } else if (fp->_flags & __SOPT) { fp->_flags |= __SOFF; fp->_offset = ret; } return (ret); }
/* * fpurge: like fflush, but without writing anything: leave the * given FILE's buffer empty. */ int fpurge(FILE *fp) { int retval; FLOCKFILE(fp); if (!fp->_flags) { errno = EBADF; retval = EOF; } else { if (HASUB(fp)) FREEUB(fp); fp->_p = fp->_bf._base; fp->_r = 0; fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size; retval = 0; } FUNLOCKFILE(fp); return (retval); }
/* * fpurge: like fflush, but without writing anything: leave the * given FILE's buffer empty. */ int fpurge(FILE *fp) { _DIAGASSERT(fp != NULL); if (fp->_flags == 0) { errno = EBADF; return EOF; } FLOCKFILE(fp); if (HASUB(fp)) FREEUB(fp); WCIO_FREE(fp); fp->_p = fp->_bf._base; fp->_r = 0; fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size; FUNLOCKFILE(fp); return 0; }
int fclose(FILE *fp) { int r; if (fp->_flags == 0) { /* not open! */ errno = EBADF; return (EOF); } FLOCKFILE(fp); r = fp->_flags & __SWR ? __sflush(fp) : 0; if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) r = EOF; if (fp->_flags & __SMBF) free((char *)fp->_bf._base); if (HASUB(fp)) FREEUB(fp); if (HASLB(fp)) FREELB(fp); fp->_file = -1; fp->_r = fp->_w = 0; /* Mess up if reaccessed. */ /* * Lock the spinlock used to protect __sglue list walk in * __sfp(). The __sfp() uses fp->_flags == 0 test as an * indication of the unused FILE. * * Taking the lock prevents possible compiler or processor * reordering of the writes performed before the final _flags * cleanup, making sure that we are done with the FILE before * it is considered available. */ STDIO_THREAD_LOCK(); fp->_flags = 0; /* Release this FILE for reuse. */ STDIO_THREAD_UNLOCK(); FUNLOCKFILE(fp); return (r); }
/* * Set one of the three kinds of buffering, optionally including * a buffer. */ int setvbuf(FILE *fp, char *buf, int mode, size_t size) { int ret, flags; size_t iosize; int ttyflag; /* * Verify arguments. The `int' limit on `size' is due to this * particular implementation. Note, buf and size are ignored * when setting _IONBF. */ if (mode != _IONBF) if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0) return (EOF); /* * Write current buffer, if any. Discard unread input (including * ungetc data), cancel line buffering, and free old buffer if * malloc()ed. We also clear any eof condition, as if this were * a seek. */ ret = 0; (void)__sflush(fp); if (HASUB(fp)) FREEUB(fp); WCIO_FREE(fp); fp->_r = fp->_lbfsize = 0; flags = fp->_flags; if (flags & __SMBF) free((void *)fp->_bf._base); flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT | __SEOF); /* If setting unbuffered mode, skip all the hard work. */ if (mode == _IONBF) goto nbf; /* * Find optimal I/O size for seek optimization. This also returns * a `tty flag' to suggest that we check isatty(fd), but we do not * care since our caller told us how to buffer. */ flags |= __swhatbuf(fp, &iosize, &ttyflag); if (size == 0) { buf = NULL; /* force local allocation */ size = iosize; } /* Allocate buffer if needed. */ if (buf == NULL) { if ((buf = malloc(size)) == NULL) { /* * Unable to honor user's request. We will return * failure, but try again with file system size. */ ret = EOF; if (size != iosize) { size = iosize; buf = malloc(size); } } if (buf == NULL) { /* No luck; switch to unbuffered I/O. */ nbf: fp->_flags = flags | __SNBF; fp->_w = 0; fp->_bf._base = fp->_p = fp->_nbuf; fp->_bf._size = 1; return (ret); } flags |= __SMBF; } /* * Kill any seek optimization if the buffer is not the * right size. * * SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? */ if (size != iosize) flags |= __SNPT; /* * Fix up the FILE fields, and set __cleanup for output flush on * exit (since we are buffered in some way). */ if (mode == _IOLBF) flags |= __SLBF; fp->_flags = flags; fp->_bf._base = fp->_p = (unsigned char *)buf; fp->_bf._size = size; /* fp->_lbfsize is still 0 */ if (flags & __SWR) { /* * Begin or continue writing: see __swsetup(). Note * that __SNBF is impossible (it was handled earlier). */ if (flags & __SLBF) { fp->_w = 0; fp->_lbfsize = -fp->_bf._size; } else fp->_w = size; } else { /* begin/continue reading, or stay in intermediate state */ fp->_w = 0; } __atexit_register_cleanup(_cleanup); return (ret); }
/* * Refill a stdio buffer. * Return EOF on eof or error, 0 otherwise. */ int __srefill(FILE *fp) { _DIAGASSERT(fp != NULL); if(fp == NULL) { errno = EINVAL; return (EOF); } /* make sure stdio is set up */ if (!__sdidinit) __sinit(); fp->_r = 0; /* largely a convenience for callers */ /* SysV does not make this test; take it out for compatibility */ if (fp->_flags & __SEOF) { return (EOF); } /* if not already reading, have to be reading and writing */ if ((fp->_flags & __SRD) == 0) { if ((fp->_flags & __SRW) == 0) { errno = EBADF; fp->_flags |= __SERR; //<dvm> Allows differentiation between errors and EOF return (EOF); } /* switch to reading */ if (fp->_flags & __SWR) { if (__sflush(fp)) { return (EOF); } fp->_flags &= ~__SWR; fp->_w = 0; fp->_lbfsize = 0; } fp->_flags |= __SRD; } else { /* * We were reading. If there is an ungetc buffer, * we must have been reading from that. Drop it, * restoring the previous buffer (if any). If there * is anything in that buffer, return. */ if (HASUB(fp)) { FREEUB(fp); if ((fp->_r = fp->_ur) != 0) { fp->_p = fp->_up; return (0); } } } if (fp->_bf._base == NULL) __smakebuf(fp); /* * Before reading from a line buffered or unbuffered file, * flush all line buffered output files, per the ANSI C * standard. */ if (fp->_flags & (__SLBF|__SNBF)) { rwlock_rdlock(&__sfp_lock); (void) _fwalk(lflush); rwlock_unlock(&__sfp_lock); } fp->_p = fp->_bf._base; fp->_r = (*fp->_read)(fp->_cookie, (char *)fp->_p, fp->_bf._size); fp->_flags &= ~__SMOD; /* buffer contents are again pristine */ if (fp->_r <= 0) { if (fp->_r == 0) fp->_flags |= __SEOF; else { fp->_r = 0; fp->_flags |= __SERR; } return (EOF); } return (0); }
/* * Seek the given file to the given offset. * `Whence' must be one of the three SEEK_* macros. */ int _fseeko(FILE *fp, off_t offset, int whence, int ltest) { fpos_t (*seekfn)(void *, fpos_t, int); fpos_t target, curoff, ret; size_t n; struct stat st; int havepos; /* * Have to be able to seek. */ if ((seekfn = fp->_seek) == NULL) { errno = ESPIPE; /* historic practice */ return (-1); } /* * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. * After this, whence is either SEEK_SET or SEEK_END. */ switch (whence) { case SEEK_CUR: /* * In order to seek relative to the current stream offset, * we have to first find the current stream offset via * ftell (see ftell for details). */ if (_ftello(fp, &curoff)) return (-1); if (curoff < 0) { /* Unspecified position because of ungetc() at 0 */ errno = ESPIPE; return (-1); } if (offset > 0 && curoff > OFF_MAX - offset) { errno = EOVERFLOW; return (-1); } offset += curoff; if (offset < 0) { errno = EINVAL; return (-1); } if (ltest && offset > LONG_MAX) { errno = EOVERFLOW; return (-1); } whence = SEEK_SET; havepos = 1; break; case SEEK_SET: if (offset < 0) { errno = EINVAL; return (-1); } case SEEK_END: curoff = 0; /* XXX just to keep gcc quiet */ havepos = 0; break; default: errno = EINVAL; return (-1); } /* * Can only optimise if: * reading (and not reading-and-writing); * not unbuffered; and * this is a `regular' Unix file (and hence seekfn==__sseek). * We must check __NBF first, because it is possible to have __NBF * and __SOPT both set. */ if (fp->_bf._base == NULL) __smakebuf(fp); if (fp->pub._flags & (__SWR | __SRW | __SNBF | __SNPT)) goto dumb; if ((fp->pub._flags & __SOPT) == 0) { if (seekfn != __sseek || fp->pub._fileno < 0 || _fstat(fp->pub._fileno, &st) || (st.st_mode & S_IFMT) != S_IFREG) { fp->pub._flags |= __SNPT; goto dumb; } fp->_blksize = st.st_blksize; fp->pub._flags |= __SOPT; } /* * We are reading; we can try to optimise. * Figure out where we are going and where we are now. */ if (whence == SEEK_SET) target = offset; else { if (_fstat(fp->pub._fileno, &st)) goto dumb; if (offset > 0 && st.st_size > OFF_MAX - offset) { errno = EOVERFLOW; return (-1); } target = st.st_size + offset; if ((off_t)target < 0) { errno = EINVAL; return (-1); } if (ltest && (off_t)target > LONG_MAX) { errno = EOVERFLOW; return (-1); } } if (!havepos && _ftello(fp, &curoff)) goto dumb; /* * (If the buffer was modified, we have to * skip this; see fgetln.c.) */ if (fp->pub._flags & __SMOD) goto abspos; /* * Compute the number of bytes in the input buffer (pretending * that any ungetc() input has been discarded). Adjust current * offset backwards by this count so that it represents the * file offset for the first byte in the current input buffer. */ if (HASUB(fp)) { curoff += fp->pub._r; /* kill off ungetc */ n = fp->_up - fp->_bf._base; curoff -= n; n += fp->_ur; } else { n = fp->pub._p - fp->_bf._base; curoff -= n; n += fp->pub._r; } /* * If the target offset is within the current buffer, * simply adjust the pointers, clear EOF, undo ungetc(), * and return. */ if (target >= curoff && target < curoff + n) { size_t o = target - curoff; fp->pub._p = fp->_bf._base + o; fp->pub._r = n - o; if (HASUB(fp)) FREEUB(fp); fp->pub._flags &= ~__SEOF; memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); return (0); } abspos: /* * The place we want to get to is not within the current buffer, * but we can still be kind to the kernel copyout mechanism. * By aligning the file offset to a block boundary, we can let * the kernel use the VM hardware to map pages instead of * copying bytes laboriously. Using a block boundary also * ensures that we only read one block, rather than two. */ curoff = target & ~(fp->_blksize - 1); if (_sseek(fp, curoff, SEEK_SET) == POS_ERR) goto dumb; fp->pub._r = 0; fp->pub._p = fp->_bf._base; if (HASUB(fp)) FREEUB(fp); n = target - curoff; if (n) { if (__srefill(fp) || fp->pub._r < n) goto dumb; fp->pub._p += n; fp->pub._r -= n; } fp->pub._flags &= ~__SEOF; memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); return (0); /* * We get here if we cannot optimise the seek ... just * do it. Allow the seek function to change fp->_bf._base. */ dumb: if (__sflush(fp) || (ret = _sseek(fp, (fpos_t)offset, whence)) == POS_ERR) return (-1); if (ltest && ret > LONG_MAX) { fp->pub._flags |= __SERR; errno = EOVERFLOW; return (-1); } /* success: clear EOF indicator and discard ungetc() data */ if (HASUB(fp)) FREEUB(fp); fp->pub._p = fp->_bf._base; fp->pub._r = 0; /* fp->pub._w = 0; */ /* unnecessary (I think...) */ fp->pub._flags &= ~__SEOF; memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); return (0); }
/* * Re-direct an existing, open (probably) file to some other file. * ANSI is written such that the original file gets closed if at * all possible, no matter what. */ FILE * freopen(const char *file, const char *mode, FILE *fp) { int f; int flags, isopen, oflags, sverrno, wantfd; if ((flags = __sflags(mode, &oflags)) == 0) { (void) fclose(fp); return (NULL); } if (!__sdidinit) __sinit(); /* * There are actually programs that depend on being able to "freopen" * descriptors that weren't originally open. Keep this from breaking. * Remember whether the stream was open to begin with, and which file * descriptor (if any) was associated with it. If it was attached to * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin) * should work. This is unnecessary if it was not a Unix file. */ if (fp->_flags == 0) { fp->_flags = __SEOF; /* hold on to it */ isopen = 0; wantfd = -1; } else { /* flush the stream; ANSI doesn't require this. */ if (fp->_flags & __SWR) (void) __sflush(fp); /* if close is NULL, closing is a no-op, hence pointless */ isopen = fp->_close != NULL; if ((wantfd = fp->_file) < 0 && isopen) { (void) (*fp->_close)(fp->_cookie); isopen = 0; } } /* Get a new descriptor to refer to the new file. */ f = open(file, oflags, DEFFILEMODE); if (f < 0 && isopen) { /* If out of fd's close the old one and try again. */ if (errno == ENFILE || errno == EMFILE) { (void) (*fp->_close)(fp->_cookie); isopen = 0; f = open(file, oflags, DEFFILEMODE); } } sverrno = errno; /* * Finish closing fp. Even if the open succeeded above, we cannot * keep fp->_base: it may be the wrong size. This loses the effect * of any setbuffer calls, but stdio has always done this before. */ if (isopen && f != wantfd) (void) (*fp->_close)(fp->_cookie); if (fp->_flags & __SMBF) free((char *)fp->_bf._base); fp->_w = 0; fp->_r = 0; fp->_p = NULL; fp->_bf._base = NULL; fp->_bf._size = 0; fp->_lbfsize = 0; if (HASUB(fp)) FREEUB(fp); _UB(fp)._size = 0; WCIO_FREE(fp); if (HASLB(fp)) FREELB(fp); fp->_lb._size = 0; if (f < 0) { /* did not get it after all */ fp->_flags = 0; /* set it free */ errno = sverrno; /* restore in case _close clobbered */ return (NULL); } /* * If reopening something that was open before on a real file, try * to maintain the descriptor. Various C library routines (perror) * assume stderr is always fd STDERR_FILENO, even if being freopen'd. */ if (wantfd >= 0 && f != wantfd) { if (dup2(f, wantfd) >= 0) { (void) close(f); f = wantfd; } } fp->_flags = flags; fp->_file = f; fp->_cookie = fp; fp->_read = __sread; fp->_write = __swrite; fp->_seek = __sseek; fp->_close = __sclose; /* * When opening in append mode, even though we use O_APPEND, * we need to seek to the end so that ftell() gets the right * answer. If the user then alters the seek pointer, or * the file extends, this will fail, but there is not much * we can do about this. (We could set __SAPP and check in * fseek and ftell.) */ if (oflags & O_APPEND) (void) __sseek((void *)fp, (fpos_t)0, SEEK_END); return (fp); }
int fseek ( FAST FILE * fp, /* stream */ long offset, /* offset from <whence> */ int whence /* position to offset from: */ /* SEEK_SET = beginning */ /* SEEK_CUR = current position */ /* SEEK_END = end-of-file */ ) { fpos_t target; fpos_t curoff; size_t n; struct stat st; int havepos; BOOL doStat; if (OBJ_VERIFY (fp, fpClassId) != OK) return (ERROR); /* * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. * After this, whence is either SEEK_SET or SEEK_END. */ switch (whence) { case SEEK_CUR: /* * In order to seek relative to the current stream offset, * we have to first find the current stream offset a la * ftell (see ftell for details). */ if (fp->_flags & __SOFF) curoff = fp->_offset; else { curoff = __sseek (fp, (fpos_t)0, SEEK_CUR); if (curoff == -1L) return (EOF); } if (fp->_flags & __SRD) { curoff -= fp->_r; if (HASUB(fp)) curoff -= fp->_ur; } else if (fp->_flags & __SWR && fp->_p != NULL) curoff += fp->_p - fp->_bf._base; offset += curoff; whence = SEEK_SET; havepos = 1; break; case SEEK_SET: case SEEK_END: curoff = 0; /* XXX just to keep gcc quiet */ havepos = 0; break; default: errno = EINVAL; return (EOF); } /* * Can only optimise if: * reading (and not reading-and-writing); * not unbuffered; and * this is a `regular' Unix file (and hence seekfn==__sseek). * We must check __NBF first, because it is possible to have __NBF * and __SOPT both set. */ if (fp->_bf._base == NULL) __smakebuf (fp); if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) goto dumb; doStat = ioctl (fp->_file, FIOFSTATGET, (int)&st); if ((fp->_flags & __SOPT) == 0) { if ((fp->_file < 0 || (doStat) || (st.st_mode & S_IFMT) != S_IFREG)) { fp->_flags |= __SNPT; goto dumb; } fp->_blksize = st.st_blksize; fp->_flags |= __SOPT; } /* * We are reading; we can try to optimise. * Figure out where we are going and where we are now. */ if (whence == SEEK_SET) target = offset; else { if (doStat) goto dumb; target = st.st_size + offset; } if (!havepos) { if (fp->_flags & __SOFF) curoff = fp->_offset; else { curoff = __sseek (fp, 0L, SEEK_CUR); if (curoff == POS_ERR) goto dumb; } curoff -= fp->_r; if (HASUB(fp)) curoff -= fp->_ur; } /* * Compute the number of bytes in the input buffer (pretending * that any ungetc() input has been discarded). Adjust current * offset backwards by this count so that it represents the * file offset for the first byte in the current input buffer. */ if (HASUB(fp)) { n = fp->_up - fp->_bf._base; curoff -= n; n += fp->_ur; } else { n = fp->_p - fp->_bf._base; curoff -= n; n += fp->_r; } /* * If the target offset is within the current buffer, * simply adjust the pointers, clear EOF, undo ungetc(), * and return. (If the buffer was modified, we have to * skip this; see fgetline.c.) */ if (((fp->_flags & __SMOD) == 0) && (target >= curoff) && (target < (curoff + n))) { FAST int o = target - curoff; fp->_p = fp->_bf._base + o; fp->_r = n - o; if (HASUB(fp)) FREEUB(fp); fp->_flags &= ~__SEOF; return (0); } /* * The place we want to get to is not within the current buffer, * but we can still be kind to the kernel copyout mechanism. * By aligning the file offset to a block boundary, we can let * the kernel use the VM hardware to map pages instead of * copying bytes laboriously. Using a block boundary also * ensures that we only read one block, rather than two. */ curoff = target & ~(fp->_blksize - 1); if (__sseek (fp, curoff, SEEK_SET) == POS_ERR) goto dumb; fp->_r = 0; if (HASUB(fp)) FREEUB(fp); fp->_flags &= ~__SEOF; n = target - curoff; if (n) { if (__srefill (fp) || fp->_r < n) goto dumb; fp->_p += n; fp->_r -= n; } return (0); /* * We get here if we cannot optimise the seek ... just * do it. Allow the seek function to change fp->_bf._base. */ dumb: if ((__sflush (fp)) || (__sseek (fp, offset, whence) == POS_ERR)) return (EOF); /* success: clear EOF indicator and discard ungetc() data */ if (HASUB(fp)) FREEUB(fp); fp->_p = fp->_bf._base; fp->_r = 0; /* fp->_w = 0; */ /* unnecessary (I think...) */ fp->_flags &= ~__SEOF; return (0); }
/* * Re-direct an existing, open (probably) file to some other file. * ANSI is written such that the original file gets closed if at * all possible, no matter what. */ FILE * freopen(const char *file, const char *mode, register FILE *fp) { register int f; int flags, isopen, oflags, sverrno, wantfd; if ((flags = __sflags(mode, &oflags)) == 0) { (void) fclose(fp); return (NULL); } if (!__sdidinit) __sinit(); /* * There are actually programs that depend on being able to "freopen" * descriptors that weren't originally open. Keep this from breaking. * Remember whether the stream was open to begin with, and which file * descriptor (if any) was associated with it. If it was attached to * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin) * should work. This is unnecessary if it was not a Unix file. */ if (fp->_flags == 0) { fp->_flags = __SEOF; /* hold on to it */ isopen = 0; wantfd = -1; } else { /* flush the stream; ANSI doesn't require this. */ if (fp->_flags & __SWR) (void) __sflush(fp); /* if close is NULL, closing is a no-op, hence pointless */ isopen = fp->_close != NULL; if ((wantfd = fp->_file) < 0 && isopen) { (void) (*fp->_close)(fp->_cookie); isopen = 0; } } /* Get a new descriptor to refer to the new file. */ #ifdef __ORCAC__ /* * ORCA/C uses "callee cleans up", so the third arg to open(2) * can be given if and only if it is expected. */ f = (oflags & O_CREAT) ? open(file, oflags, DEFFILEMODE) : open(file, oflags); #else f = open(file, oflags, DEFFILEMODE); #endif if (f < 0 && isopen) { /* If out of fd's close the old one and try again. */ #ifdef __GNO__ if (errno == EMFILE) { /* no ENFILE for GNO */ #else if (errno == ENFILE || errno == EMFILE) { #endif (void) (*fp->_close)(fp->_cookie); isopen = 0; f = open(file, oflags, DEFFILEMODE); } } sverrno = errno; /* * Finish closing fp. Even if the open succeeded above, we cannot * keep fp->_base: it may be the wrong size. This loses the effect * of any setbuffer calls, but stdio has always done this before. */ if (isopen) (void) (*fp->_close)(fp->_cookie); if (fp->_flags & __SMBF) free((char *)fp->_bf._base); fp->_w = 0; fp->_r = 0; fp->_p = NULL; fp->_bf._base = NULL; fp->_bf._size = 0; fp->_lbfsize = 0; if (HASUB(fp)) FREEUB(fp); fp->_ub._size = 0; if (HASLB(fp)) FREELB(fp); fp->_lb._size = 0; if (f < 0) { /* did not get it after all */ fp->_flags = 0; /* set it free */ errno = sverrno; /* restore in case _close clobbered */ return (NULL); } /* * If reopening something that was open before on a real file, try * to maintain the descriptor. Various C library routines (perror) * assume stderr is always fd STDERR_FILENO, even if being freopen'd. */ if (wantfd >= 0 && f != wantfd) { if (dup2(f, wantfd) >= 0) { (void) close(f); f = wantfd; } } fp->_flags = flags; fp->_file = f; fp->_cookie = fp; fp->_read = __sread; fp->_write = __swrite; fp->_seek = __sseek; fp->_close = __sclose; return (fp); }
FILE *freopen( const char *filename, const char *mode, FILE *stream ) { register int f; int wantfd, isopen, flags, oflags, e; if (filename == NULL || filename[0] == '\0') return NULL; EXCL_START(&stream->_file_lock); if ((flags = __sflags(mode, &oflags)) == 0) { EXCL_END(&stream->_file_lock); (void) fclose(stream); return NULL; } if (!__sdidinit) __sinit(); /* * Remember whether the stream was open to begin with, and * which file descriptor (if any) was associated with it. * If it was attached to a descriptor, defer closing it, * so that, e.g., freopen("/dev/stdin", "r", stdin) works. * This is unnecessary if it was not a Unix file. */ if (stream->_flags == 0) { stream->_flags = __SEOF; /* hold on to it */ isopen = 0; wantfd = -1; } else { if (stream->_flags & __SWR) (void) _fflush(stream); /* if close is NULL, closing is a no-op, hence pointless */ isopen = stream->_close != NULL; if ((wantfd = stream->_file) < 0 && isopen) { (void) (*stream->_close)(stream->_cookie); isopen = 0; } } /* * Now get a new descriptor to refer to the new file. */ f = _open(filename, oflags, 0666); if (f < 0 && isopen) { /* * May have used up all descriptors, so close the old * and try again. */ (void) (*stream->_close)(stream->_cookie); isopen = 0; f = _open(filename, oflags, 0666); } e = errno; /* * Finish closing stream. Even if the open succeeded above, * we cannot keep stream->_base: it may be the wrong size. * This loses the effect of any setbuffer calls, * but stdio has always done this before. */ if (isopen) (void) (*stream->_close)(stream->_cookie); if (stream->_flags & __SMBF) free((char *)stream->_bf._base); stream->_w = 0; stream->_r = 0; stream->_p = NULL; stream->_bf._base = NULL; stream->_bf._size = 0; stream->_lbfsize = 0; if (HASUB(stream)) FREEUB(stream); stream->_ub._size = 0; if (HASLB(stream)) FREELB(stream); stream->_lb._size = 0; if (f < 0) { /* did not get it after all */ stream->_flags = 0; /* set it free */ errno = e; /* restore in case _close clobbered */ EXCL_END(&stream->_file_lock); return NULL; } #ifdef NOTDEF /* * If reopening something that was open before on a real file, * try to maintain the descriptor. Various routines (e.g., * perror) assume that after `freopen(name, mode, stderr)', * fileno(stderr)==2. */ if (wantfd >= 0 && f != wantfd) { if (_dup2(f, wantfd) >= 0) { (void) _close(f); f = wantfd; } } #endif /* NOTDEF */ stream->_flags = flags; stream->_file = f; stream->_cookie = stream; stream->_read = __sread; stream->_write = __swrite; stream->_seek = __sseek; stream->_close = __sclose; EXCL_END(&stream->_file_lock); return stream; }
FILE * _freopen64_r (struct _reent *ptr, const char *file, const char *mode, register FILE *fp) { register int f; int flags, oflags, oflags2; int e = 0; CHECK_INIT (ptr, fp); /* We can't use the _newlib_flockfile_XXX macros here due to the interlocked locking with the sfp_lock. */ #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT int __oldcancel; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldcancel); #endif oflags2 = fp->_flags2; if (!(oflags2 & __SNLK)) _flockfile (fp); if ((flags = __sflags (ptr, mode, &oflags)) == 0) { if (!(oflags2 & __SNLK)) _funlockfile (fp); #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT pthread_setcancelstate (__oldcancel, &__oldcancel); #endif _fclose_r (ptr, fp); return NULL; } /* * Remember whether the stream was open to begin with, and * which file descriptor (if any) was associated with it. * If it was attached to a descriptor, defer closing it, * so that, e.g., freopen("/dev/stdin", "r", stdin) works. * This is unnecessary if it was not a Unix file. */ if (fp->_flags == 0) fp->_flags = __SEOF; /* hold on to it */ else { if (fp->_flags & __SWR) _fflush_r (ptr, fp); /* * If close is NULL, closing is a no-op, hence pointless. * If file is NULL, the file should not be closed. */ if (fp->_close != NULL && file != NULL) fp->_close (ptr, fp->_cookie); } /* * Now get a new descriptor to refer to the new file, or reuse the * existing file descriptor if file is NULL. */ if (file != NULL) { f = _open64_r (ptr, (char *) file, oflags, 0666); e = __errno_r(ptr); } else { #ifdef HAVE_FCNTL int oldflags; /* * Reuse the file descriptor, but only if the new access mode is * equal or less permissive than the old. F_SETFL correctly * ignores creation flags. */ f = fp->_file; if ((oldflags = _fcntl_r (ptr, f, F_GETFL, 0)) == -1 || ! ((oldflags & O_ACCMODE) == O_RDWR || ((oldflags ^ oflags) & O_ACCMODE) == 0) || _fcntl_r (ptr, f, F_SETFL, oflags) == -1) f = -1; #else /* We cannot modify without fcntl support. */ f = -1; #endif #ifdef __SCLE /* * F_SETFL doesn't change textmode. Don't mess with modes of ttys. */ if (0 <= f && ! isatty (f) && setmode (f, oflags & (O_BINARY | O_TEXT)) == -1) f = -1; #endif if (f < 0) { e = EBADF; if (fp->_close != NULL) fp->_close (ptr, fp->_cookie); } } /* * Finish closing fp. Even if the open succeeded above, * we cannot keep fp->_base: it may be the wrong size. * This loses the effect of any setbuffer calls, * but stdio has always done this before. */ if (fp->_flags & __SMBF) _free_r (ptr, (char *) fp->_bf._base); fp->_w = 0; fp->_r = 0; fp->_p = NULL; fp->_bf._base = NULL; fp->_bf._size = 0; fp->_lbfsize = 0; if (HASUB (fp)) FREEUB (ptr, fp); fp->_ub._size = 0; if (HASLB (fp)) FREELB (ptr, fp); fp->_lb._size = 0; fp->_flags &= ~__SORD; fp->_flags2 &= ~__SWID; memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); if (f < 0) { /* did not get it after all */ __sfp_lock_acquire (); fp->_flags = 0; /* set it free */ __errno_r(ptr) = e; /* restore in case _close clobbered */ if (!(oflags2 & __SNLK)) _funlockfile (fp); #ifndef __SINGLE_THREAD__ __lock_close_recursive (fp->_lock); #endif __sfp_lock_release (); #if !defined (__SINGLE_THREAD__) && defined (_POSIX_THREADS) pthread_setcancelstate (__oldcancel, &__oldcancel); #endif return NULL; } fp->_flags = flags; fp->_file = f; fp->_cookie = (void *) fp; fp->_read = __sread; fp->_write = __swrite64; fp->_seek = __sseek; fp->_seek64 = __sseek64; fp->_close = __sclose; #ifdef __SCLE if (__stextmode(fp->_file)) fp->_flags |= __SCLE; #endif fp->_flags |= __SL64; if (!(oflags2 & __SNLK)) _funlockfile (fp); #if !defined (__SINGLE_THREAD__) && defined (_POSIX_THREADS) pthread_setcancelstate (__oldcancel, &__oldcancel); #endif return fp; }
int __srefill (register FILE * fp) { /* make sure stdio is set up */ CHECK_INIT (fp); fp->_r = 0; /* largely a convenience for callers */ /* SysV does not make this test; take it out for compatibility */ if (fp->_flags & __SEOF) return EOF; /* if not already reading, have to be reading and writing */ if ((fp->_flags & __SRD) == 0) { if ((fp->_flags & __SRW) == 0) return EOF; /* switch to reading */ if (fp->_flags & __SWR) { if (fflush (fp)) return EOF; fp->_flags &= ~__SWR; fp->_w = 0; fp->_lbfsize = 0; } fp->_flags |= __SRD; } else { /* * We were reading. If there is an ungetc buffer, * we must have been reading from that. Drop it, * restoring the previous buffer (if any). If there * is anything in that buffer, return. */ if (HASUB (fp)) { FREEUB (fp); if ((fp->_r = fp->_ur) != 0) { fp->_p = fp->_up; return 0; } } } if (fp->_bf._base == NULL) __smakebuf (fp); /* * Before reading from a line buffered or unbuffered file, * flush all line buffered output files, per the ANSI C * standard. */ if (fp->_flags & (__SLBF | __SNBF)) (void) _fwalk (fp->_data, lflush); fp->_p = fp->_bf._base; fp->_r = (*fp->_read) (fp->_cookie, (char *) fp->_p, fp->_bf._size); fp->_flags &= ~__SMOD; /* buffer contents are again pristine */ if (fp->_r <= 0) { if (fp->_r == 0) fp->_flags |= __SEOF; else { fp->_r = 0; fp->_flags |= __SERR; } return EOF; } return 0; }
/* * Seek the given file to the given offset. * `Whence' must be one of the three SEEK_* macros. */ int fseeko(FILE *fp, off_t offset, int whence) { fpos_t (*seekfn)(void *, fpos_t, int); fpos_t target, curoff; size_t n; struct stat st; int havepos; /* make sure stdio is set up */ if (!__sdidinit) __sinit(); /* * Have to be able to seek. */ if ((seekfn = fp->_seek) == NULL || isatty(__sfileno(fp))) { __sseterr(fp, ESPIPE); /* historic practice */ return (EOF); } /* * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. * After this, whence is either SEEK_SET or SEEK_END. */ FLOCKFILE(fp); switch (whence) { case SEEK_CUR: /* * In order to seek relative to the current stream offset, * we have to first find the current stream offset a la * ftell (see ftell for details). */ __sflush(fp); /* may adjust seek offset on append stream */ if (fp->_flags & __SOFF) curoff = fp->_offset; else { curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR); if (curoff == (fpos_t)-1) { FUNLOCKFILE(fp); return (EOF); } } if (fp->_flags & __SRD) { curoff -= fp->_r; if (HASUB(fp)) curoff -= fp->_ur; } else if (fp->_flags & __SWR && fp->_p != NULL) curoff += fp->_p - fp->_bf._base; offset += curoff; whence = SEEK_SET; havepos = 1; break; case SEEK_SET: case SEEK_END: curoff = 0; /* XXX just to keep gcc quiet */ havepos = 0; break; default: FUNLOCKFILE(fp); __sseterr(fp, EINVAL); return (EOF); } /* * Can only optimise if: * reading (and not reading-and-writing); * not unbuffered; and * this is a `regular' Unix file (and hence seekfn==__sseek). * We must check __NBF first, because it is possible to have __NBF * and __SOPT both set. */ if (fp->_bf._base == NULL) __smakebuf(fp); if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) goto dumb; if ((fp->_flags & __SOPT) == 0) { if (seekfn != __sseek || fp->_file < 0 || __libc_fstat(fp->_file, &st) || (st.st_mode & S_IFMT) != S_IFREG) { fp->_flags |= __SNPT; goto dumb; } fp->_blksize = st.st_blksize; fp->_flags |= __SOPT; } /* * We are reading; we can try to optimise. * Figure out where we are going and where we are now. */ if (whence == SEEK_SET) target = offset; else { if (__libc_fstat(fp->_file, &st)) goto dumb; target = st.st_size + offset; } if (!havepos) { if (fp->_flags & __SOFF) curoff = fp->_offset; else { curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR); if (curoff == POS_ERR) goto dumb; } curoff -= fp->_r; if (HASUB(fp)) curoff -= fp->_ur; } /* * Compute the number of bytes in the input buffer (pretending * that any ungetc() input has been discarded). Adjust current * offset backwards by this count so that it represents the * file offset for the first byte in the current input buffer. */ if (HASUB(fp)) { curoff += fp->_r; /* kill off ungetc */ n = fp->_up - fp->_bf._base; curoff -= n; n += fp->_ur; } else { n = fp->_p - fp->_bf._base; curoff -= n; n += fp->_r; } /* * If the target offset is within the current buffer, * simply adjust the pointers, clear EOF, undo ungetc(), * and return. (If the buffer was modified, we have to * skip this; see fgetln.c.) */ if ((fp->_flags & __SMOD) == 0 && target >= curoff && target < curoff + n) { int o = target - curoff; fp->_p = fp->_bf._base + o; fp->_r = n - o; if (HASUB(fp)) FREEUB(fp); fp->_flags &= ~__SEOF; FUNLOCKFILE(fp); return (0); } /* * The place we want to get to is not within the current buffer, * but we can still be kind to the kernel copyout mechanism. * By aligning the file offset to a block boundary, we can let * the kernel use the VM hardware to map pages instead of * copying bytes laboriously. Using a block boundary also * ensures that we only read one block, rather than two. */ curoff = target & ~(fp->_blksize - 1); if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR) goto dumb; fp->_r = 0; fp->_p = fp->_bf._base; if (HASUB(fp)) FREEUB(fp); fp->_flags &= ~__SEOF; n = target - curoff; if (n) { if (__srefill(fp) || fp->_r < n) goto dumb; fp->_p += n; fp->_r -= n; } FUNLOCKFILE(fp); return (0); /* * We get here if we cannot optimise the seek ... just * do it. Allow the seek function to change fp->_bf._base. */ dumb: if (__sflush(fp) || (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) { FUNLOCKFILE(fp); return (EOF); } /* success: clear EOF indicator and discard ungetc() data */ if (HASUB(fp)) FREEUB(fp); fp->_p = fp->_bf._base; fp->_r = 0; /* fp->_w = 0; */ /* unnecessary (I think...) */ fp->_flags &= ~__SEOF; FUNLOCKFILE(fp); return (0); }
/* * Refill a stdio buffer. * Return EOF on eof or error, 0 otherwise. */ int __srefill(FILE *fp) { /* make sure stdio is set up */ if (!__sdidinit) __sinit(); ORIENT(fp, -1); fp->_r = 0; /* largely a convenience for callers */ /* SysV does not make this test; take it out for compatibility */ if (fp->_flags & __SEOF) return (EOF); /* if not already reading, have to be reading and writing */ if ((fp->_flags & __SRD) == 0) { if ((fp->_flags & __SRW) == 0) { errno = EBADF; fp->_flags |= __SERR; return (EOF); } /* switch to reading */ if (fp->_flags & __SWR) { if (__sflush(fp)) return (EOF); fp->_flags &= ~__SWR; fp->_w = 0; fp->_lbfsize = 0; } fp->_flags |= __SRD; } else { /* * We were reading. If there is an ungetc buffer, * we must have been reading from that. Drop it, * restoring the previous buffer (if any). If there * is anything in that buffer, return. */ if (HASUB(fp)) { FREEUB(fp); if ((fp->_r = fp->_ur) != 0) { fp->_p = fp->_up; return (0); } } } if (fp->_bf._base == NULL) __smakebuf(fp); /* * Before reading from a line buffered or unbuffered file, * flush all line buffered output files, per the ANSI C * standard. */ if (fp->_flags & (__SLBF|__SNBF)) { /* Ignore this file in _fwalk to avoid potential deadlock. */ fp->_flags |= __SIGN; (void) _fwalk(lflush); fp->_flags &= ~__SIGN; /* Now flush this file without locking it. */ if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) __sflush(fp); } fp->_p = fp->_bf._base; fp->_r = _sread(fp, (char *)fp->_p, fp->_bf._size); fp->_flags &= ~__SMOD; /* buffer contents are again pristine */ if (fp->_r <= 0) { if (fp->_r == 0) fp->_flags |= __SEOF; else { fp->_r = 0; fp->_flags |= __SERR; } return (EOF); } return (0); }