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 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