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