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