1 /*
2 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
3 This program and the accompanying materials are licensed and made available
4 under the terms and conditions of the BSD License that accompanies this
5 distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11 * Copyright (c) 1990, 1993
12 * The Regents of the University of California. All rights reserved.
13 *
14 * This code is derived from software contributed to Berkeley by
15 * Chris Torek.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40
41 NetBSD: fseeko.c,v 1.5 2005/03/04 16:04:58 dsl Exp
42 */
43 //#include <Uefi.h> // REMOVE, For DEBUG only
44 //#include <Library/UefiLib.h> // REMOVE, For DEBUG only
45
46 #include <LibConfig.h>
47 #include <sys/EfiCdefs.h>
48
49 #include "namespace.h"
50 #include <sys/types.h>
51 #include <sys/stat.h>
52
53 #include <assert.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include "reentrant.h"
59 #include "local.h"
60
61 #ifdef __weak_alias
__weak_alias(fseeko,_fseeko)62 __weak_alias(fseeko, _fseeko)
63 #endif
64
65 #define POS_ERR (-(fpos_t)1)
66
67 /*
68 * Seek the given file to the given offset.
69 * `Whence' must be one of the three SEEK_* macros.
70 */
71 int
72 fseeko(FILE *fp, off_t offset, int whence)
73 {
74 fpos_t (*seekfn)(void *, fpos_t, int);
75 fpos_t target, curoff;
76 size_t n;
77 struct stat st;
78 int havepos;
79
80 _DIAGASSERT(fp != NULL);
81 if(fp == NULL) {
82 errno = EINVAL;
83 return -1;
84 }
85
86 #ifdef __GNUC__
87 /* This outrageous construct just to shut up a GCC warning. */
88 (void) &curoff;
89 #endif
90
91 /* make sure stdio is set up */
92 if (!__sdidinit)
93 __sinit();
94
95 //Print(L"%a( %d, %Ld, %d)\n", __func__, fp->_file, offset, whence);
96 FLOCKFILE(fp);
97
98 /*
99 * Have to be able to seek.
100 */
101 if ((seekfn = fp->_seek) == NULL) {
102 errno = ESPIPE; /* historic practice */
103 FUNLOCKFILE(fp);
104 //Print(L"%a: %d\n", __func__, __LINE__);
105 return (-1);
106 }
107
108 /*
109 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
110 * After this, whence is either SEEK_SET or SEEK_END.
111 */
112 switch (whence) {
113
114 case SEEK_CUR:
115 /*
116 * In order to seek relative to the current stream offset,
117 * we have to first find the current stream offset a la
118 * ftell (see ftell for details).
119 */
120 __sflush(fp); /* may adjust seek offset on append stream */
121 if (fp->_flags & __SOFF)
122 curoff = fp->_offset;
123 else {
124 curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
125 if (curoff == POS_ERR) {
126 FUNLOCKFILE(fp);
127 //Print(L"%a: %d\n", __func__, __LINE__);
128 return (-1);
129 }
130 }
131 if (fp->_flags & __SRD) {
132 curoff -= fp->_r;
133 if (HASUB(fp))
134 curoff -= fp->_ur;
135 } else if (fp->_flags & __SWR && fp->_p != NULL)
136 curoff += fp->_p - fp->_bf._base;
137
138 offset += curoff;
139 whence = SEEK_SET;
140 havepos = 1;
141 break;
142
143 case SEEK_SET:
144 case SEEK_END:
145 curoff = 0; /* XXX just to keep gcc quiet */
146 havepos = 0;
147 break;
148
149 default:
150 errno = EINVAL;
151 FUNLOCKFILE(fp);
152 //Print(L"%a: %d\n", __func__, __LINE__);
153 return (-1);
154 }
155
156 /*
157 * Can only optimise if:
158 * reading (and not reading-and-writing);
159 * not unbuffered; and
160 * this is a `regular' Unix file (and hence seekfn==__sseek).
161 * We must check __NBF first, because it is possible to have __NBF
162 * and __SOPT both set.
163 */
164 if (fp->_bf._base == NULL)
165 __smakebuf(fp);
166 if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
167 goto dumb;
168 if ((fp->_flags & __SOPT) == 0) {
169 if (seekfn != __sseek ||
170 fp->_file < 0 || fstat(fp->_file, &st) ||
171 !S_ISREG(st.st_mode)) {
172 fp->_flags |= __SNPT;
173 goto dumb;
174 }
175 fp->_blksize = st.st_blksize;
176 fp->_flags |= __SOPT;
177 }
178
179 /*
180 * We are reading; we can try to optimise.
181 * Figure out where we are going and where we are now.
182 */
183 if (whence == SEEK_SET)
184 target = offset;
185 else {
186 if (fstat(fp->_file, &st))
187 {
188 //Print(L"%a: %d\n", __func__, __LINE__);
189 goto dumb;
190 }
191 target = st.st_size + offset;
192 }
193
194 if (!havepos) {
195 if (fp->_flags & __SOFF)
196 curoff = fp->_offset;
197 else {
198 curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
199 if (curoff == POS_ERR)
200 {
201 //Print(L"%a: %d\n", __func__, __LINE__);
202 goto dumb;
203 }
204 }
205 curoff -= fp->_r;
206 if (HASUB(fp))
207 curoff -= fp->_ur;
208 }
209
210 /*
211 * Compute the number of bytes in the input buffer (pretending
212 * that any ungetc() input has been discarded). Adjust current
213 * offset backwards by this count so that it represents the
214 * file offset for the first byte in the current input buffer.
215 */
216 if (HASUB(fp)) {
217 curoff += fp->_r; /* kill off ungetc */
218 n = fp->_up - fp->_bf._base;
219 curoff -= n;
220 n += fp->_ur;
221 } else {
222 n = fp->_p - fp->_bf._base;
223 curoff -= n;
224 n += fp->_r;
225 }
226
227 /*
228 * If the target offset is within the current buffer,
229 * simply adjust the pointers, clear EOF, undo ungetc(),
230 * and return. (If the buffer was modified, we have to
231 * skip this; see fgetln.c.)
232 */
233 if ((fp->_flags & __SMOD) == 0 &&
234 target >= curoff && target < (fpos_t)(curoff + n)) {
235 int o = (int)(target - curoff);
236
237 fp->_p = fp->_bf._base + o;
238 fp->_r = (int)(n - o);
239 if (HASUB(fp))
240 FREEUB(fp);
241 WCIO_FREE(fp); /* Should this really be unconditional??? */
242 fp->_flags &= ~__SEOF;
243 FUNLOCKFILE(fp);
244 return (0);
245 }
246
247 /*
248 * The place we want to get to is not within the current buffer,
249 * but we can still be kind to the kernel copyout mechanism.
250 * By aligning the file offset to a block boundary, we can let
251 * the kernel use the VM hardware to map pages instead of
252 * copying bytes laboriously. Using a block boundary also
253 * ensures that we only read one block, rather than two.
254 */
255 curoff = target & ~(fp->_blksize - 1);
256 if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR)
257 {
258 //Print(L"%a: %d\n", __func__, __LINE__);
259 goto dumb;
260 }
261 fp->_r = 0;
262 fp->_p = fp->_bf._base;
263 if (HASUB(fp))
264 FREEUB(fp);
265 WCIO_FREE(fp); /* Should this really be unconditional??? */
266 fp->_flags &= ~__SEOF;
267 n = (int)(target - curoff);
268 if (n) {
269 if (__srefill(fp) || fp->_r < (int)n)
270 {
271 //Print(L"%a: %d\n", __func__, __LINE__);
272 goto dumb;
273 }
274 fp->_p += n;
275 fp->_r -= (int)n;
276 }
277 FUNLOCKFILE(fp);
278 return (0);
279
280 /*
281 * We get here if we cannot optimise the seek ... just
282 * do it. Allow the seek function to change fp->_bf._base.
283 */
284 dumb:
285 //Print(L"%a: %d\n", __func__, __LINE__);
286 if (__sflush(fp) ||
287 (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) {
288 FUNLOCKFILE(fp);
289 //Print(L"%a: %d\n", __func__, __LINE__);
290 return (-1);
291 }
292 /* success: clear EOF indicator and discard ungetc() data */
293 if (HASUB(fp))
294 FREEUB(fp);
295 WCIO_FREE(fp); /* Should this really be unconditional??? */
296 fp->_p = fp->_bf._base;
297 fp->_r = 0;
298 fp->_w = 0;
299 fp->_flags &= ~__SEOF;
300 FUNLOCKFILE(fp);
301 //Print(L"%a: %d\n", __func__, __LINE__);
302 return (0);
303 }
304