gonzui


Format: Advanced Search

t2ex/bsd_source/lib/libc/src_bsd/stdio/fseek.cbare sourcepermlink (0.04 seconds)

Search this content:

    1: /*      $OpenBSD: fseek.c,v 1.10 2009/11/09 00:18:27 kurt Exp $ */
    2: /*-
    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: 
   34: #include <sys/types.h>
   35: #include <sys/stat.h>
   36: #include <fcntl.h>
   37: #include <stdio.h>
   38: #include <stdlib.h>
   39: #include <errno.h>
   40: #include "local.h"
   41: 
   42: #define POS_ERR (-(fpos_t)1)
   43: 
   44: /*
   45:  * Seek the given file to the given offset.
   46:  * `Whence' must be one of the three SEEK_* macros.
   47:  */
   48: int
   49: fseeko(FILE *fp, off_t offset, int whence)
   50: {
   51:         fpos_t (*seekfn)(void *, fpos_t, int);
   52:         fpos_t target, curoff;
   53:         size_t n;
   54:         struct stat st;
   55:         int havepos;
   56: 
   57:         /* make sure stdio is set up */
   58:         if (!__sdidinit)
   59:                 __sinit();
   60: 
   61:         /*
   62:          * Have to be able to seek.
   63:          */
   64:         if ((seekfn = fp->_seek) == NULL || isatty(__sfileno(fp))) {
   65:                 __sseterr(fp, ESPIPE);                        /* historic practice */
   66:                 return (EOF);
   67:         }
   68: 
   69:         /*
   70:          * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
   71:          * After this, whence is either SEEK_SET or SEEK_END.
   72:          */
   73:         FLOCKFILE(fp);
   74:         switch (whence) {
   75: 
   76:         case SEEK_CUR:
   77:                 /*
   78:                  * In order to seek relative to the current stream offset,
   79:                  * we have to first find the current stream offset a la
   80:                  * ftell (see ftell for details).
   81:                  */
   82:                 __sflush(fp); /* may adjust seek offset on append stream */
   83:                 if (fp->_flags & __SOFF)
   84:                         curoff = fp->_offset;
   85:                 else {
   86:                         curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
   87:                         if (curoff == (fpos_t)-1) {
   88:                                 FUNLOCKFILE(fp);
   89:                                 return (EOF);
   90:                         }
   91:                 }
   92:                 if (fp->_flags & __SRD) {
   93:                         curoff -= fp->_r;
   94:                         if (HASUB(fp))
   95:                                 curoff -= fp->_ur;
   96:                 } else if (fp->_flags & __SWR && fp->_p != NULL)
   97:                         curoff += fp->_p - fp->_bf._base;
   98: 
   99:                 offset += curoff;
  100:                 whence = SEEK_SET;
  101:                 havepos = 1;
  102:                 break;
  103: 
  104:         case SEEK_SET:
  105:         case SEEK_END:
  106:                 curoff = 0;           /* XXX just to keep gcc quiet */
  107:                 havepos = 0;
  108:                 break;
  109: 
  110:         default:
  111:                 FUNLOCKFILE(fp);
  112:                 __sseterr(fp, EINVAL);
  113:                 return (EOF);
  114:         }
  115: 
  116:         /*
  117:          * Can only optimise if:
  118:          *     reading (and not reading-and-writing);
  119:          *     not unbuffered; and
  120:          *     this is a `regular' Unix file (and hence seekfn==__sseek).
  121:          * We must check __NBF first, because it is possible to have __NBF
  122:          * and __SOPT both set.
  123:          */
  124:         if (fp->_bf._base == NULL)
  125:                 __smakebuf(fp);
  126:         if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
  127:                 goto dumb;
  128:         if ((fp->_flags & __SOPT) == 0) {
  129:                 if (seekfn != __sseek ||
  130:                     fp->_file < 0 || __libc_fstat(fp->_file, &st) ||
  131:                     (st.st_mode & S_IFMT) != S_IFREG) {
  132:                         fp->_flags |= __SNPT;
  133:                         goto dumb;
  134:                 }
  135:                 fp->_blksize = st.st_blksize;
  136:                 fp->_flags |= __SOPT;
  137:         }
  138: 
  139:         /*
  140:          * We are reading; we can try to optimise.
  141:          * Figure out where we are going and where we are now.
  142:          */
  143:         if (whence == SEEK_SET)
  144:                 target = offset;
  145:         else {
  146:                 if (__libc_fstat(fp->_file, &st))
  147:                         goto dumb;
  148:                 target = st.st_size + offset;
  149:         }
  150: 
  151:         if (!havepos) {
  152:                 if (fp->_flags & __SOFF)
  153:                         curoff = fp->_offset;
  154:                 else {
  155:                         curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
  156:                         if (curoff == POS_ERR)
  157:                                 goto dumb;
  158:                 }
  159:                 curoff -= fp->_r;
  160:                 if (HASUB(fp))
  161:                         curoff -= fp->_ur;
  162:         }
  163: 
  164:         /*
  165:          * Compute the number of bytes in the input buffer (pretending
  166:          * that any ungetc() input has been discarded).  Adjust current
  167:          * offset backwards by this count so that it represents the
  168:          * file offset for the first byte in the current input buffer.
  169:          */
  170:         if (HASUB(fp)) {
  171:                 curoff += fp->_r;     /* kill off ungetc */
  172:                 n = fp->_up - fp->_bf._base;
  173:                 curoff -= n;
  174:                 n += fp->_ur;
  175:         } else {
  176:                 n = fp->_p - fp->_bf._base;
  177:                 curoff -= n;
  178:                 n += fp->_r;
  179:         }
  180: 
  181:         /*
  182:          * If the target offset is within the current buffer,
  183:          * simply adjust the pointers, clear EOF, undo ungetc(),
  184:          * and return.  (If the buffer was modified, we have to
  185:          * skip this; see fgetln.c.)
  186:          */
  187:         if ((fp->_flags & __SMOD) == 0 &&
  188:             target >= curoff && target < curoff + n) {
  189:                 int o = target - curoff;
  190: 
  191:                 fp->_p = fp->_bf._base + o;
  192:                 fp->_r = n - o;
  193:                 if (HASUB(fp))
  194:                         FREEUB(fp);
  195:                 fp->_flags &= ~__SEOF;
  196:                 FUNLOCKFILE(fp);
  197:                 return (0);
  198:         }
  199: 
  200:         /*
  201:          * The place we want to get to is not within the current buffer,
  202:          * but we can still be kind to the kernel copyout mechanism.
  203:          * By aligning the file offset to a block boundary, we can let
  204:          * the kernel use the VM hardware to map pages instead of
  205:          * copying bytes laboriously.  Using a block boundary also
  206:          * ensures that we only read one block, rather than two.
  207:          */
  208:         curoff = target & ~(fp->_blksize - 1);
  209:         if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR)
  210:                 goto dumb;
  211:         fp->_r = 0;
  212:         fp->_p = fp->_bf._base;
  213:         if (HASUB(fp))
  214:                 FREEUB(fp);
  215:         fp->_flags &= ~__SEOF;
  216:         n = target - curoff;
  217:         if (n) {
  218:                 if (__srefill(fp) || fp->_r < n)
  219:                         goto dumb;
  220:                 fp->_p += n;
  221:                 fp->_r -= n;
  222:         }
  223:         FUNLOCKFILE(fp);
  224:         return (0);
  225: 
  226:         /*
  227:          * We get here if we cannot optimise the seek ... just
  228:          * do it.  Allow the seek function to change fp->_bf._base.
  229:          */
  230: dumb:
  231:         if (__sflush(fp) ||
  232:             (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) {
  233:                 FUNLOCKFILE(fp);
  234:                 return (EOF);
  235:         }
  236:         /* success: clear EOF indicator and discard ungetc() data */
  237:         if (HASUB(fp))
  238:                 FREEUB(fp);
  239:         fp->_p = fp->_bf._base;
  240:         fp->_r = 0;
  241:         /* fp->_w = 0; */      /* unnecessary (I think...) */
  242:         fp->_flags &= ~__SEOF;
  243:         FUNLOCKFILE(fp);
  244:         return (0);
  245: }
  246: 
  247: /*
  248:  * fseek()'s offset is a long and sizeof(off_t) != sizeof(long) on all arches
  249:  */
  250: #if defined(__alpha__) && defined(__indr_reference)
  251: __indr_reference(fseeko, fseek);
  252: #else
  253: int
  254: fseek(FILE *fp, long offset, int whence)
  255: {
  256:         off_t off = offset;
  257: 
  258:         return(fseeko(fp, off, whence));
  259: }
  260: #endif
  261: __weak_alias(fseek64, fseeko);