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); }
/* * 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); }
/* * 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; }
/* * 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); }
/* * 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); }
/* * 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; _DIAGASSERT(fp != NULL); if(fp == NULL) { errno = EINVAL; return -1; } #ifdef __GNUC__ /* This outrageous construct just to shut up a GCC warning. */ (void) &curoff; #endif /* make sure stdio is set up */ if (!__sdidinit) __sinit(); //Print(L"%a( %d, %Ld, %d)\n", __func__, fp->_file, offset, whence); FLOCKFILE(fp); /* * Have to be able to seek. */ if ((seekfn = fp->_seek) == NULL) { errno = ESPIPE; /* historic practice */ FUNLOCKFILE(fp); //Print(L"%a: %d\n", __func__, __LINE__); 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 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 == POS_ERR) { FUNLOCKFILE(fp); //Print(L"%a: %d\n", __func__, __LINE__); return (-1); } } 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; FUNLOCKFILE(fp); //Print(L"%a: %d\n", __func__, __LINE__); 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->_flags & (__SWR | __SRW | __SNBF | __SNPT)) goto dumb; if ((fp->_flags & __SOPT) == 0) { if (seekfn != __sseek || fp->_file < 0 || fstat(fp->_file, &st) || !S_ISREG(st.st_mode)) { 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 (fstat(fp->_file, &st)) { //Print(L"%a: %d\n", __func__, __LINE__); 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) { //Print(L"%a: %d\n", __func__, __LINE__); 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 < (fpos_t)(curoff + n)) { int o = (int)(target - curoff); fp->_p = fp->_bf._base + o; fp->_r = (int)(n - o); if (HASUB(fp)) FREEUB(fp); WCIO_FREE(fp); /* Should this really be unconditional??? */ 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) { //Print(L"%a: %d\n", __func__, __LINE__); goto dumb; } fp->_r = 0; fp->_p = fp->_bf._base; if (HASUB(fp)) FREEUB(fp); WCIO_FREE(fp); /* Should this really be unconditional??? */ fp->_flags &= ~__SEOF; n = (int)(target - curoff); if (n) { if (__srefill(fp) || fp->_r < (int)n) { //Print(L"%a: %d\n", __func__, __LINE__); goto dumb; } fp->_p += n; fp->_r -= (int)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: //Print(L"%a: %d\n", __func__, __LINE__); if (__sflush(fp) || (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) { FUNLOCKFILE(fp); //Print(L"%a: %d\n", __func__, __LINE__); return (-1); } /* success: clear EOF indicator and discard ungetc() data */ if (HASUB(fp)) FREEUB(fp); WCIO_FREE(fp); /* Should this really be unconditional??? */ fp->_p = fp->_bf._base; fp->_r = 0; fp->_w = 0; fp->_flags &= ~__SEOF; FUNLOCKFILE(fp); //Print(L"%a: %d\n", __func__, __LINE__); return (0); }