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