1 /* 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 /* 19 FUNCTION 20 <<fseeko64>>---set file position for large file 21 22 INDEX 23 fseeko64 24 INDEX 25 _fseeko64_r 26 27 ANSI_SYNOPSIS 28 #include <stdio.h> 29 int fseeko64(FILE *<[fp]>, _off64_t <[offset]>, int <[whence]>) 30 int _fseeko64_r (struct _reent *<[ptr]>, FILE *<[fp]>, 31 _off64_t <[offset]>, int <[whence]>) 32 TRAD_SYNOPSIS 33 #include <stdio.h> 34 35 int fseeko64(<[fp]>, <[offset]>, <[whence]>) 36 FILE *<[fp]>; 37 _off64_t <[offset]>; 38 int <[whence]>; 39 40 int _fseeko64_r (<[ptr]>, <[fp]>, <[offset]>, <[whence]>) 41 struct _reent *<[ptr]>; 42 FILE *<[fp]>; 43 _off64_t <[offset]>; 44 int <[whence]>; 45 46 DESCRIPTION 47 Objects of type <<FILE>> can have a ``position'' that records how much 48 of the file your program has already read. Many of the <<stdio>> functions 49 depend on this position, and many change it as a side effect. 50 51 You can use <<fseeko64>> to set the position for the file identified by 52 <[fp]> that was opened via <<fopen64>>. The value of <[offset]> determines 53 the new position, in one of three ways selected by the value of <[whence]> 54 (defined as macros in `<<stdio.h>>'): 55 56 <<SEEK_SET>>---<[offset]> is the absolute file position (an offset 57 from the beginning of the file) desired. <[offset]> must be positive. 58 59 <<SEEK_CUR>>---<[offset]> is relative to the current file position. 60 <[offset]> can meaningfully be either positive or negative. 61 62 <<SEEK_END>>---<[offset]> is relative to the current end of file. 63 <[offset]> can meaningfully be either positive (to increase the size 64 of the file) or negative. 65 66 See <<ftello64>> to determine the current file position. 67 68 RETURNS 69 <<fseeko64>> returns <<0>> when successful. On failure, the 70 result is <<EOF>>. The reason for failure is indicated in <<errno>>: 71 either <<ESPIPE>> (the stream identified by <[fp]> doesn't support 72 repositioning or wasn't opened via <<fopen64>>) or <<EINVAL>> 73 (invalid file position). 74 75 PORTABILITY 76 <<fseeko64>> is a glibc extension. 77 78 Supporting OS subroutines required: <<close>>, <<fstat64>>, <<isatty>>, 79 <<lseek64>>, <<read>>, <<sbrk>>, <<write>>. 80 */ 81 82 #include <stdio.h> 83 #include <time.h> 84 #include <fcntl.h> 85 #include <stdlib.h> 86 #include <errno.h> 87 #include <sys/types.h> 88 #include <sys/stat.h> 89 #include "local64.h" 90 91 #define POS_ERR (-(_fpos64_t)1) 92 93 #ifdef __LARGE64_FILES 94 95 /* 96 * Seek the given file to the given offset. 97 * `Whence' must be one of the three SEEK_* macros. 98 */ 99 100 _off64_t 101 _DEFUN (_fseeko64_r, (ptr, fp, offset, whence), 102 struct _reent *ptr _AND 103 register FILE *fp _AND 104 _off64_t offset _AND 105 int whence) 106 { 107 _fpos64_t _EXFUN ((*seekfn), (void *, _fpos64_t, int)); 108 _fpos64_t target, curoff; 109 size_t n; 110 111 struct stat64 st; 112 int havepos; 113 114 _flockfile(fp); 115 116 /* Make sure stdio is set up. */ 117 118 CHECK_INIT (fp); 119 120 curoff = fp->_offset; 121 122 /* If we've been doing some writing, and we're in append mode 123 then we don't really know where the filepos is. */ 124 125 if (fp->_flags & __SAPP && fp->_flags & __SWR) 126 { 127 /* So flush the buffer and seek to the end. */ 128 fflush (fp); 129 } 130 131 /* Have to be able to seek. */ 132 133 if ((seekfn = fp->_seek64) == NULL || !(fp->_flags & __SL64)) 134 { 135 ptr->_errno = ESPIPE; /* ??? */ 136 _funlockfile(fp); 137 return EOF; 138 } 139 140 /* 141 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. 142 * After this, whence is either SEEK_SET or SEEK_END. 143 */ 144 145 switch (whence) 146 { 147 case SEEK_CUR: 148 /* 149 * In order to seek relative to the current stream offset, 150 * we have to first find the current stream offset a la 151 * ftell (see ftell for details). 152 */ 153 fflush(fp); /* may adjust seek offset on append stream */ 154 if (fp->_flags & __SOFF) 155 curoff = fp->_offset; 156 else 157 { 158 curoff = (*seekfn) (fp->_cookie, (_fpos64_t) 0, SEEK_CUR); 159 if (curoff == -1L) 160 { 161 _funlockfile(fp); 162 return EOF; 163 } 164 } 165 if (fp->_flags & __SRD) 166 { 167 curoff -= fp->_r; 168 if (HASUB (fp)) 169 curoff -= fp->_ur; 170 } 171 else if (fp->_flags & __SWR && fp->_p != NULL) 172 curoff += fp->_p - fp->_bf._base; 173 174 offset += curoff; 175 whence = SEEK_SET; 176 havepos = 1; 177 break; 178 179 case SEEK_SET: 180 case SEEK_END: 181 havepos = 0; 182 break; 183 184 default: 185 ptr->_errno = EINVAL; 186 _funlockfile(fp); 187 return (EOF); 188 } 189 190 /* 191 * Can only optimise if: 192 * reading (and not reading-and-writing); 193 * not unbuffered; and 194 * this is a `regular' Unix file (and hence seekfn==__sseek). 195 * We must check __NBF first, because it is possible to have __NBF 196 * and __SOPT both set. 197 */ 198 199 if (fp->_bf._base == NULL) 200 __smakebuf (fp); 201 if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) 202 goto dumb; 203 if ((fp->_flags & __SOPT) == 0) 204 { 205 if (seekfn != __sseek64 206 || fp->_file < 0 207 || _fstat64_r (ptr, fp->_file, &st) 208 || (st.st_mode & S_IFMT) != S_IFREG) 209 { 210 fp->_flags |= __SNPT; 211 goto dumb; 212 } 213 #ifdef HAVE_BLKSIZE 214 fp->_blksize = st.st_blksize; 215 #else 216 fp->_blksize = 1024; 217 #endif 218 fp->_flags |= __SOPT; 219 } 220 221 /* 222 * We are reading; we can try to optimise. 223 * Figure out where we are going and where we are now. 224 */ 225 226 if (whence == SEEK_SET) 227 target = offset; 228 else 229 { 230 if (_fstat64_r (ptr, fp->_file, &st)) 231 goto dumb; 232 target = st.st_size + offset; 233 } 234 235 if (!havepos) 236 { 237 if (fp->_flags & __SOFF) 238 curoff = fp->_offset; 239 else 240 { 241 curoff = (*seekfn) (fp->_cookie, (_fpos64_t)0, SEEK_CUR); 242 if (curoff == POS_ERR) 243 goto dumb; 244 } 245 curoff -= fp->_r; 246 if (HASUB (fp)) 247 curoff -= fp->_ur; 248 } 249 250 /* 251 * Compute the number of bytes in the input buffer (pretending 252 * that any ungetc() input has been discarded). Adjust current 253 * offset backwards by this count so that it represents the 254 * file offset for the first byte in the current input buffer. 255 */ 256 257 if (HASUB (fp)) 258 { 259 curoff += fp->_r; /* kill off ungetc */ 260 n = fp->_up - fp->_bf._base; 261 curoff -= n; 262 n += fp->_ur; 263 } 264 else 265 { 266 n = fp->_p - fp->_bf._base; 267 curoff -= n; 268 n += fp->_r; 269 } 270 271 /* 272 * If the target offset is within the current buffer, 273 * simply adjust the pointers, clear EOF, undo ungetc(), 274 * and return. (If the buffer was modified, we have to 275 * skip this; see fgetline.c.) 276 */ 277 278 if ((fp->_flags & __SMOD) == 0 && 279 target >= curoff && target < curoff + n) 280 { 281 register int o = target - curoff; 282 283 fp->_p = fp->_bf._base + o; 284 fp->_r = n - o; 285 if (HASUB (fp)) 286 FREEUB (fp); 287 fp->_flags &= ~__SEOF; 288 _funlockfile(fp); 289 return 0; 290 } 291 292 /* 293 * The place we want to get to is not within the current buffer, 294 * but we can still be kind to the kernel copyout mechanism. 295 * By aligning the file offset to a block boundary, we can let 296 * the kernel use the VM hardware to map pages instead of 297 * copying bytes laboriously. Using a block boundary also 298 * ensures that we only read one block, rather than two. 299 */ 300 301 curoff = target & ~((_fpos64_t)(fp->_blksize - 1)); 302 if ((*seekfn) (fp->_cookie, curoff, SEEK_SET) == POS_ERR) 303 goto dumb; 304 fp->_r = 0; 305 fp->_p = fp->_bf._base; 306 if (HASUB (fp)) 307 FREEUB (fp); 308 fp->_flags &= ~__SEOF; 309 n = target - curoff; 310 if (n) 311 { 312 if (__srefill (fp) || fp->_r < n) 313 goto dumb; 314 fp->_p += n; 315 fp->_r -= n; 316 } 317 _funlockfile(fp); 318 return 0; 319 320 /* 321 * We get here if we cannot optimise the seek ... just 322 * do it. Allow the seek function to change fp->_bf._base. 323 */ 324 325 dumb: 326 if (fflush (fp) || (*seekfn) (fp->_cookie, offset, whence) == POS_ERR) 327 { 328 _funlockfile(fp); 329 return EOF; 330 } 331 /* success: clear EOF indicator and discard ungetc() data */ 332 if (HASUB (fp)) 333 FREEUB (fp); 334 fp->_p = fp->_bf._base; 335 fp->_r = 0; 336 /* fp->_w = 0; *//* unnecessary (I think...) */ 337 fp->_flags &= ~__SEOF; 338 _funlockfile(fp); 339 return 0; 340 } 341 342 #ifndef _REENT_ONLY 343 344 _off64_t 345 _DEFUN (fseeko64, (fp, offset, whence), 346 register FILE *fp _AND 347 _off64_t offset _AND 348 int whence) 349 { 350 return _fseeko64_r (_REENT, fp, offset, whence); 351 } 352 353 #endif /* !_REENT_ONLY */ 354 355 #endif /* __LARGE64_FILES */ 356