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