Ejemplo n.º 1
0
FILE *
fopen(const char *file, const char *mode)
{
	FILE *fp;
	int f;
	int flags, oflags;

	if ((flags = __sflags(mode, &oflags)) == 0)
		return (NULL);
	if ((fp = __sfp()) == NULL)
		return (NULL);
	if ((f = open(file, oflags, DEFFILEMODE)) < 0) {
		fp->_flags = 0;			/* release */
		return (NULL);
	}
	fp->_file = f;
	fp->_flags = flags;
	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);
}
Ejemplo n.º 2
0
FILE *
fopen(const char *file, const char *mode)
{
  FILE *fp;
  int f;
  int flags, oflags;

  _DIAGASSERT(file != NULL);
  if ((flags = __sflags(mode, &oflags)) == 0)
    return (NULL);
  if ((fp = __sfp()) == NULL)
    return (NULL);
  if ((f = open(file, oflags, DEFFILEMODE)) < 0)
    goto release;
  if (oflags & O_NONBLOCK) {
    struct stat st;
    if (fstat(f, &st) == -1) {
      int sverrno = errno;
      (void)close(f);
      errno = sverrno;
      goto release;
    }
    if (!S_ISREG(st.st_mode)) {
      (void)close(f);
      errno = EFTYPE;
      goto release;
    }
  }
  fp->_file = (short)f;
  fp->_flags = (unsigned short)flags;
  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);
release:
  fp->_flags = 0;     /* release */
  return (NULL);
}
Ejemplo n.º 3
0
long ftell
(
    FAST FILE *  fp	/* stream */
)
{
    FAST fpos_t pos;

    if (OBJ_VERIFY (fp, fpClassId) != OK)
        return (ERROR);

    /*
     * Find offset of underlying I/O object, then
     * adjust for buffered bytes.
     */

    if (fp->_flags & __SOFF)
        pos = fp->_offset;
    else
    {
        pos = __sseek (fp, (fpos_t)0, SEEK_CUR);

        if (pos == -1L)
            return (pos);
    }

    if (fp->_flags & __SRD)
    {
        /*
         * Reading.  Any unread characters (including
         * those from ungetc) cause the position to be
         * smaller than that in the underlying object.
         */

        pos -= fp->_r;

        if (HASUB(fp))
            pos -= fp->_ur;
    }
    else if (fp->_flags & __SWR && fp->_p != NULL)
    {
        /*
         * Writing.  Any buffered characters cause the
         * position to be greater than that in the
         * underlying object.
         */

        pos += fp->_p - fp->_bf._base;
    }

    return (pos);
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
0
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);
    }