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 | * 4. Neither the name of the University nor the names of its contributors␊ |
17 | * may be used to endorse or promote products derived from this software␊ |
18 | * without specific prior written permission.␊ |
19 | *␊ |
20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND␊ |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE␊ |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE␊ |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE␊ |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL␊ |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS␊ |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)␊ |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT␊ |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY␊ |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF␊ |
30 | * SUCH DAMAGE.␊ |
31 | */␊ |
32 | ␊ |
33 | #if defined(LIBC_SCCS) && !defined(lint)␊ |
34 | static char sccsid[] = "@(#)fseek.c␉8.3 (Berkeley) 1/2/94";␊ |
35 | #endif /* LIBC_SCCS and not lint */␊ |
36 | #include <sys/cdefs.h>␊ |
37 | //__FBSDID("$FreeBSD: src/lib/libc/stdio/fseek.c,v 1.44 2008/04/17 22:17:54 jhb Exp $");␊ |
38 | ␊ |
39 | #include "namespace.h"␊ |
40 | #include <sys/types.h>␊ |
41 | #include <limits.h>␊ |
42 | #include "stdio.h"␊ |
43 | #include "errno.h"␊ |
44 | #include "un-namespace.h"␊ |
45 | #include "local.h"␊ |
46 | #include "stat.h"␊ |
47 | #include "_fbsd_compat_.h"␊ |
48 | ␊ |
49 | ␊ |
50 | #define␉POS_ERR␉(-(fpos_t)1)␊ |
51 | ␊ |
52 | int␊ |
53 | fseek(fp, offset, whence)␊ |
54 | ␉FILE *fp;␊ |
55 | ␉long offset;␊ |
56 | ␉int whence;␊ |
57 | {␊ |
58 | ␉int ret;␊ |
59 | ␉int serrno = get_errno();␊ |
60 | ␊ |
61 | ␉/* make sure stdio is set up */␊ |
62 | ␉if (!__sdidinit)␊ |
63 | ␉␉__sinit();␊ |
64 | ␊ |
65 | ␉ret = _fseeko(fp, (off_t)offset, whence, 1);␊ |
66 | ␉if (ret == 0)␊ |
67 | ␉␉set_errno(serrno);␊ |
68 | ␉return (ret);␊ |
69 | }␊ |
70 | ␊ |
71 | int␊ |
72 | fseeko(fp, offset, whence)␊ |
73 | ␉FILE *fp;␊ |
74 | ␉off_t offset;␊ |
75 | ␉int whence;␊ |
76 | {␊ |
77 | ␉int ret;␊ |
78 | int serrno = get_errno();␊ |
79 | ␊ |
80 | ␉/* make sure stdio is set up */␊ |
81 | ␉if (!__sdidinit)␊ |
82 | ␉␉__sinit();␊ |
83 | ␊ |
84 | ␉ret = _fseeko(fp, offset, whence, 0);␊ |
85 | ␉if (ret == 0)␊ |
86 | ␉␉set_errno(serrno);␊ |
87 | ␊ |
88 | ␉return (ret);␊ |
89 | }␊ |
90 | ␊ |
91 | /*␊ |
92 | * Seek the given file to the given offset.␊ |
93 | * `Whence' must be one of the three SEEK_* macros.␊ |
94 | */␊ |
95 | int␊ |
96 | _fseeko(fp, offset, whence, ltest)␊ |
97 | ␉FILE *fp;␊ |
98 | ␉off_t offset;␊ |
99 | ␉int whence;␊ |
100 | ␉int ltest;␊ |
101 | {␊ |
102 | ␉fpos_t (*seekfn)(void *, fpos_t, int);␊ |
103 | ␉fpos_t target, curoff, ret;␊ |
104 | ␉size_t n;␊ |
105 | ␉struct stat st;␊ |
106 | ␉int havepos;␊ |
107 | ␊ |
108 | ␉/*␊ |
109 | ␉ * Have to be able to seek.␊ |
110 | ␉ */␊ |
111 | ␉if ((seekfn = fp->_seek) == NULL) {␊ |
112 | ␉␉set_errno(ESPIPE);␊ |
113 | return (-1);␊ |
114 | ␉}␊ |
115 | ␊ |
116 | ␉/*␊ |
117 | ␉ * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.␊ |
118 | ␉ * After this, whence is either SEEK_SET or SEEK_END.␊ |
119 | ␉ */␊ |
120 | ␉switch (whence) {␊ |
121 | ␊ |
122 | ␉case SEEK_CUR:␊ |
123 | ␉␉/*␊ |
124 | ␉␉ * In order to seek relative to the current stream offset,␊ |
125 | ␉␉ * we have to first find the current stream offset via␊ |
126 | ␉␉ * ftell (see ftell for details).␊ |
127 | ␉␉ */␊ |
128 | ␉␉if (_ftello(fp, &curoff))␊ |
129 | ␉␉␉return (-1);␊ |
130 | ␉␉if (curoff < 0) {␊ |
131 | ␉␉␉/* Unspecified position because of ungetc() at 0 */␊ |
132 | set_errno(ESPIPE);␊ |
133 | ␉␉␉return (-1);␊ |
134 | ␉␉}␊ |
135 | ␉␉if (offset > 0 && curoff > OFF_MAX - offset) {␊ |
136 | set_errno(EOVERFLOW);␊ |
137 | ␉␉␉return (-1);␊ |
138 | ␉␉}␊ |
139 | ␉␉offset += curoff;␊ |
140 | ␉␉if (offset < 0) {␊ |
141 | set_errno(EINVAL);␊ |
142 | ␉␉␉return (-1);␊ |
143 | ␉␉}␊ |
144 | ␉␉if (ltest && offset > LONG_MAX) {␊ |
145 | set_errno(EOVERFLOW);␊ |
146 | ␉␉␉return (-1);␊ |
147 | ␉␉}␊ |
148 | ␉␉whence = SEEK_SET;␊ |
149 | ␉␉havepos = 1;␊ |
150 | ␉␉break;␊ |
151 | ␊ |
152 | ␉case SEEK_SET:␊ |
153 | ␉␉if (offset < 0) {␊ |
154 | set_errno(EINVAL);␊ |
155 | ␉␉␉return (-1);␊ |
156 | ␉␉}␊ |
157 | ␉case SEEK_END:␊ |
158 | ␉␉curoff = 0;␉␉/* XXX just to keep gcc quiet */␊ |
159 | ␉␉havepos = 0;␊ |
160 | ␉␉break;␊ |
161 | ␊ |
162 | ␉default: ␊ |
163 | set_errno(EINVAL);␊ |
164 | ␉␉return (-1);␊ |
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 0␊ |
180 | ␉if ((fp->_flags & __SOPT) == 0) {␊ |
181 | ␉␉if (seekfn != __sseek ||␊ |
182 | ␉␉ fp->_file < 0 || _fstat(fp->_file, &st) ||␊ |
183 | ␉␉ (st.st_mode & S_IFMT) != S_IFREG) {␊ |
184 | ␉␉␉fp->_flags |= __SNPT;␊ |
185 | ␉␉␉goto dumb;␊ |
186 | ␉␉}␊ |
187 | ␉␉fp->_blksize = st.st_blksize;␊ |
188 | ␉␉fp->_flags |= __SOPT;␊ |
189 | ␉}␊ |
190 | #else␊ |
191 | fp->_flags |= __SNPT;␊ |
192 | goto dumb;␊ |
193 | #endif␊ |
194 | ␊ |
195 | ␉/*␊ |
196 | ␉ * We are reading; we can try to optimise.␊ |
197 | ␉ * Figure out where we are going and where we are now.␊ |
198 | ␉ */␊ |
199 | ␉if (whence == SEEK_SET)␊ |
200 | ␉␉target = offset;␊ |
201 | ␉else {␊ |
202 | ␉␉if (_fstat(fp->_file, &st))␊ |
203 | ␉␉␉goto dumb;␊ |
204 | ␉␉if (offset > 0 && st.st_size > OFF_MAX - offset) {␊ |
205 | set_errno(EOVERFLOW);␊ |
206 | ␉␉␉return (-1);␊ |
207 | ␉␉}␊ |
208 | ␉␉target = st.st_size + offset;␊ |
209 | ␉␉if ((off_t)target < 0) {␊ |
210 | set_errno(EINVAL);␊ |
211 | ␉␉␉return (-1);␊ |
212 | ␉␉}␊ |
213 | ␉␉if (ltest && (off_t)target > LONG_MAX) {␊ |
214 | set_errno(EOVERFLOW);␊ |
215 | ␉␉␉return (-1);␊ |
216 | ␉␉}␊ |
217 | ␉}␊ |
218 | ␊ |
219 | ␉if (!havepos && _ftello(fp, &curoff))␊ |
220 | ␉␉goto dumb;␊ |
221 | ␊ |
222 | ␉/*␊ |
223 | ␉ * (If the buffer was modified, we have to␊ |
224 | ␉ * skip this; see fgetln.c.)␊ |
225 | ␉ */␊ |
226 | ␉if (fp->_flags & __SMOD)␊ |
227 | ␉␉goto abspos;␊ |
228 | ␊ |
229 | ␉/*␊ |
230 | ␉ * Compute the number of bytes in the input buffer (pretending␊ |
231 | ␉ * that any ungetc() input has been discarded). Adjust current␊ |
232 | ␉ * offset backwards by this count so that it represents the␊ |
233 | ␉ * file offset for the first byte in the current input buffer.␊ |
234 | ␉ */␊ |
235 | ␉if (HASUB(fp)) {␊ |
236 | ␉␉curoff += fp->_r;␉/* kill off ungetc */␊ |
237 | ␉␉n = fp->_up - fp->_bf._base;␊ |
238 | ␉␉curoff -= n;␊ |
239 | ␉␉n += fp->_ur;␊ |
240 | ␉} else {␊ |
241 | ␉␉n = fp->_p - fp->_bf._base;␊ |
242 | ␉␉curoff -= n;␊ |
243 | ␉␉n += fp->_r;␊ |
244 | ␉}␊ |
245 | ␊ |
246 | ␉/*␊ |
247 | ␉ * If the target offset is within the current buffer,␊ |
248 | ␉ * simply adjust the pointers, clear EOF, undo ungetc(),␊ |
249 | ␉ * and return.␊ |
250 | ␉ */␊ |
251 | ␉if (target >= curoff && target < curoff + n) {␊ |
252 | ␉␉size_t o = target - curoff;␊ |
253 | ␊ |
254 | ␉␉fp->_p = fp->_bf._base + o;␊ |
255 | ␉␉fp->_r = n - o;␊ |
256 | ␉␉if (HASUB(fp))␊ |
257 | ␉␉␉FREEUB(fp);␊ |
258 | ␉␉fp->_flags &= ~__SEOF;␊ |
259 | ␉␉memset(&fp->_mbstate, 0, sizeof(mbstate_t));␊ |
260 | ␉␉return (0);␊ |
261 | ␉}␊ |
262 | ␊ |
263 | abspos:␊ |
264 | ␉/*␊ |
265 | ␉ * The place we want to get to is not within the current buffer,␊ |
266 | ␉ * but we can still be kind to the kernel copyout mechanism.␊ |
267 | ␉ * By aligning the file offset to a block boundary, we can let␊ |
268 | ␉ * the kernel use the VM hardware to map pages instead of␊ |
269 | ␉ * copying bytes laboriously. Using a block boundary also␊ |
270 | ␉ * ensures that we only read one block, rather than two.␊ |
271 | ␉ */␊ |
272 | ␉curoff = target & ~(fp->_blksize - 1);␊ |
273 | ␉if (_sseek(fp, curoff, SEEK_SET) == POS_ERR)␊ |
274 | ␉␉goto dumb;␊ |
275 | ␉fp->_r = 0;␊ |
276 | ␉fp->_p = fp->_bf._base;␊ |
277 | ␉if (HASUB(fp))␊ |
278 | ␉␉FREEUB(fp);␊ |
279 | ␉n = target - curoff;␊ |
280 | ␉if (n) {␊ |
281 | ␉␉if (__srefill(fp) || fp->_r < n)␊ |
282 | ␉␉␉goto dumb;␊ |
283 | ␉␉fp->_p += n;␊ |
284 | ␉␉fp->_r -= n;␊ |
285 | ␉}␊ |
286 | ␉fp->_flags &= ~__SEOF;␊ |
287 | ␉memset(&fp->_mbstate, 0, sizeof(mbstate_t));␊ |
288 | ␉return (0);␊ |
289 | ␊ |
290 | ␉/*␊ |
291 | ␉ * We get here if we cannot optimise the seek ... just␊ |
292 | ␉ * do it. Allow the seek function to change fp->_bf._base.␊ |
293 | ␉ */␊ |
294 | dumb:␊ |
295 | ␉if (__sflush(fp) ||␊ |
296 | ␉ (ret = _sseek(fp, (fpos_t)offset, whence)) == POS_ERR)␊ |
297 | ␉␉return (-1);␊ |
298 | ␉if (ltest && ret > LONG_MAX) {␊ |
299 | ␉␉fp->_flags |= __SERR;␊ |
300 | set_errno(EOVERFLOW);␊ |
301 | ␉␉return (-1);␊ |
302 | ␉}␊ |
303 | ␉/* success: clear EOF indicator and discard ungetc() data */␊ |
304 | ␉if (HASUB(fp))␊ |
305 | ␉␉FREEUB(fp);␊ |
306 | ␉fp->_p = fp->_bf._base;␊ |
307 | ␉fp->_r = 0;␊ |
308 | ␉/* fp->_w = 0; */␉/* unnecessary (I think...) */␊ |
309 | ␉fp->_flags &= ~__SEOF;␊ |
310 | ␉memset(&fp->_mbstate, 0, sizeof(mbstate_t));␊ |
311 | ␉return (0);␊ |
312 | }␊ |
313 | |