fseek.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       fseek.c (6896B)
       ---
            1 /*-
            2  * Copyright (c) 1990, 1993
            3  *        The Regents of the University of California.  All rights reserved.
            4  *
            5  * This code is derived from software contributed to Berkeley by
            6  * Chris Torek.
            7  *
            8  * Redistribution and use in source and binary forms, with or without
            9  * modification, are permitted provided that the following conditions
           10  * are met:
           11  * 1. Redistributions of source code must retain the above copyright
           12  *    notice, this list of conditions and the following disclaimer.
           13  * 2. Redistributions in binary form must reproduce the above copyright
           14  *    notice, this list of conditions and the following disclaimer in the
           15  *    documentation and/or other materials provided with the distribution.
           16  * 3. All advertising materials mentioning features or use of this software
           17  *    must display the following acknowledgement:
           18  *        This product includes software developed by the University of
           19  *        California, Berkeley and its contributors.
           20  * 4. Neither the name of the University nor the names of its contributors
           21  *    may be used to endorse or promote products derived from this software
           22  *    without specific prior written permission.
           23  *
           24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
           25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
           26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
           27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
           28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
           29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
           30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
           31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
           32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
           33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
           34  * SUCH DAMAGE.
           35  */
           36 
           37 #if defined(LIBC_SCCS) && !defined(lint)
           38 static char rcsid[] = "$OpenBSD: fseek.c,v 1.2 1996/08/19 08:32:46 tholo Exp $";
           39 #endif /* LIBC_SCCS and not lint */
           40 
           41 #include <sys/types.h>
           42 #include <sys/stat.h>
           43 #include <fcntl.h>
           44 #include <stdio.h>
           45 #include <stdlib.h>
           46 #include <errno.h>
           47 #include "local.h"
           48 
           49 #define        POS_ERR        (-(fpos_t)1)
           50 
           51 /*
           52  * Seek the given file to the given offset.
           53  * `Whence' must be one of the three SEEK_* macros.
           54  */
           55 int
           56 fseek(fp, offset, whence)
           57         register FILE *fp;
           58         long offset;
           59         int whence;
           60 {
           61         register fpos_t (*seekfn) __P((void *, fpos_t, int));
           62         fpos_t target, curoff;
           63         size_t n;
           64         struct stat st;
           65         int havepos;
           66 
           67         /* make sure stdio is set up */
           68         if (!__sdidinit)
           69                 __sinit();
           70 
           71         /*
           72          * Have to be able to seek.
           73          */
           74         if ((seekfn = fp->_seek) == NULL) {
           75                 errno = ESPIPE;                        /* historic practice */
           76                 return (EOF);
           77         }
           78 
           79         /*
           80          * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
           81          * After this, whence is either SEEK_SET or SEEK_END.
           82          */
           83         switch (whence) {
           84 
           85         case SEEK_CUR:
           86                 /*
           87                  * In order to seek relative to the current stream offset,
           88                  * we have to first find the current stream offset a la
           89                  * ftell (see ftell for details).
           90                  */
           91                 __sflush(fp);        /* may adjust seek offset on append stream */
           92                 if (fp->_flags & __SOFF)
           93                         curoff = fp->_offset;
           94                 else {
           95                         curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
           96                         if (curoff == -1L)
           97                                 return (EOF);
           98                 }
           99                 if (fp->_flags & __SRD) {
          100                         curoff -= fp->_r;
          101                         if (HASUB(fp))
          102                                 curoff -= fp->_ur;
          103                 } else if (fp->_flags & __SWR && fp->_p != NULL)
          104                         curoff += fp->_p - fp->_bf._base;
          105 
          106                 offset += curoff;
          107                 whence = SEEK_SET;
          108                 havepos = 1;
          109                 break;
          110 
          111         case SEEK_SET:
          112         case SEEK_END:
          113                 curoff = 0;                /* XXX just to keep gcc quiet */
          114                 havepos = 0;
          115                 break;
          116 
          117         default:
          118                 errno = EINVAL;
          119                 return (EOF);
          120         }
          121 
          122         /*
          123          * Can only optimise if:
          124          *        reading (and not reading-and-writing);
          125          *        not unbuffered; and
          126          *        this is a `regular' Unix file (and hence seekfn==__sseek).
          127          * We must check __NBF first, because it is possible to have __NBF
          128          * and __SOPT both set.
          129          */
          130         if (fp->_bf._base == NULL)
          131                 __smakebuf(fp);
          132         if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
          133                 goto dumb;
          134         if ((fp->_flags & __SOPT) == 0) {
          135                 if (seekfn != __sseek ||
          136                     fp->_file < 0 || fstat(fp->_file, &st) ||
          137                     (st.st_mode & S_IFMT) != S_IFREG) {
          138                         fp->_flags |= __SNPT;
          139                         goto dumb;
          140                 }
          141                 fp->_blksize = st.st_blksize;
          142                 fp->_flags |= __SOPT;
          143         }
          144 
          145         /*
          146          * We are reading; we can try to optimise.
          147          * Figure out where we are going and where we are now.
          148          */
          149         if (whence == SEEK_SET)
          150                 target = offset;
          151         else {
          152                 if (fstat(fp->_file, &st))
          153                         goto dumb;
          154                 target = st.st_size + offset;
          155         }
          156 
          157         if (!havepos) {
          158                 if (fp->_flags & __SOFF)
          159                         curoff = fp->_offset;
          160                 else {
          161                         curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
          162                         if (curoff == POS_ERR)
          163                                 goto dumb;
          164                 }
          165                 curoff -= fp->_r;
          166                 if (HASUB(fp))
          167                         curoff -= fp->_ur;
          168         }
          169 
          170         /*
          171          * Compute the number of bytes in the input buffer (pretending
          172          * that any ungetc() input has been discarded).  Adjust current
          173          * offset backwards by this count so that it represents the
          174          * file offset for the first byte in the current input buffer.
          175          */
          176         if (HASUB(fp)) {
          177                 curoff += fp->_r;        /* kill off ungetc */
          178                 n = fp->_up - fp->_bf._base;
          179                 curoff -= n;
          180                 n += fp->_ur;
          181         } else {
          182                 n = fp->_p - fp->_bf._base;
          183                 curoff -= n;
          184                 n += fp->_r;
          185         }
          186 
          187         /*
          188          * If the target offset is within the current buffer,
          189          * simply adjust the pointers, clear EOF, undo ungetc(),
          190          * and return.  (If the buffer was modified, we have to
          191          * skip this; see fgetln.c.)
          192          */
          193         if ((fp->_flags & __SMOD) == 0 &&
          194             target >= curoff && target < curoff + n) {
          195                 register int o = target - curoff;
          196 
          197                 fp->_p = fp->_bf._base + o;
          198                 fp->_r = n - o;
          199                 if (HASUB(fp))
          200                         FREEUB(fp);
          201                 fp->_flags &= ~__SEOF;
          202                 return (0);
          203         }
          204 
          205         /*
          206          * The place we want to get to is not within the current buffer,
          207          * but we can still be kind to the kernel copyout mechanism.
          208          * By aligning the file offset to a block boundary, we can let
          209          * the kernel use the VM hardware to map pages instead of
          210          * copying bytes laboriously.  Using a block boundary also
          211          * ensures that we only read one block, rather than two.
          212          */
          213         curoff = target & ~(fp->_blksize - 1);
          214         if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR)
          215                 goto dumb;
          216         fp->_r = 0;
          217          fp->_p = fp->_bf._base;
          218         if (HASUB(fp))
          219                 FREEUB(fp);
          220         fp->_flags &= ~__SEOF;
          221         n = target - curoff;
          222         if (n) {
          223                 if (__srefill(fp) || fp->_r < n)
          224                         goto dumb;
          225                 fp->_p += n;
          226                 fp->_r -= n;
          227         }
          228         return (0);
          229 
          230         /*
          231          * We get here if we cannot optimise the seek ... just
          232          * do it.  Allow the seek function to change fp->_bf._base.
          233          */
          234 dumb:
          235         if (__sflush(fp) ||
          236             (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) {
          237                 return (EOF);
          238         }
          239         /* success: clear EOF indicator and discard ungetc() data */
          240         if (HASUB(fp))
          241                 FREEUB(fp);
          242         fp->_p = fp->_bf._base;
          243         fp->_r = 0;
          244         /* fp->_w = 0; */        /* unnecessary (I think...) */
          245         fp->_flags &= ~__SEOF;
          246         return (0);
          247 }