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