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