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