Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
9.5 KiB

  1. /***
  2. *fseek.c - reposition file pointer on a stream
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines fseek() - move the file pointer to new place in file
  8. *
  9. *Revision History:
  10. * 10-13-83 RN initial version
  11. * 06-26-85 TC added code to allow variable buffer lengths
  12. * 02-10-87 BCM fixed '%' mistakenly used for '/'
  13. * 03-04-87 JCR added errno settings
  14. * 04-16-87 JCR added _IOUNGETC support for bug fix and changes whence
  15. * from unsigned int to int (ANSI conformance)
  16. * 04-17-87 JCR fseek() now clears end-of-file indicator flag _IOEOF
  17. * (for ANSI conformance)
  18. * 04-21-87 JCR be smart about lseek'ing to the end of the file and
  19. * back
  20. * 09-17-87 SKS handle case of '\n' at beginning of buffer (FCRLF flag)
  21. * 09-24-87 JCR fixed an incorrect access to flag _IOEOF
  22. * 09-28-87 JCR Corrected _iob2 indexing (now uses _iob_index() macro).
  23. * 09-30-87 JCR Fixed buffer allocation bug, now use _getbuf()
  24. * 11-04-87 JCR Multi-thread support
  25. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  26. * 01-13-88 JCR Removed unnecessary calls to mthread fileno/feof/ferror
  27. * 03-04-88 JCR Return value from read() must be treated as unsigned
  28. * value
  29. * 05-27-88 PHG Merged DLL and normal versions
  30. * 06-06-88 JCR Optimized _iob2[] references
  31. * 06-15-88 JCR Near reference to _iob[] entries; improve REG variables
  32. * 08-25-88 GJF Don't use FP_OFF() macro for the 386
  33. * 12-02-88 JCR Added _IOCTRLZ support (fixes bug pertaining to ^Z at
  34. * eof)
  35. * 04-12-89 JCR Ripped out all of the special read-only code. See the
  36. * comments in the routine header for more information.
  37. * 08-17-89 GJF Clean up, now specific to OS/2 2.0 (i.e., 386 flat
  38. * model). Also fixed copyright and indents.
  39. * 02-15-90 GJF Fixed copyright
  40. * 03-19-90 GJF Made calling type _CALLTYPE1, added #include
  41. * <cruntime.h> and removed #include <register.h>.
  42. * 05-29-90 SBM Use _flush, not [_]fflush[_lk]
  43. * 07-23-90 SBM Replaced <assertm.h> by <assert.h>
  44. * 10-02-90 GJF New-style function declarators.
  45. * 01-21-91 GJF ANSI naming.
  46. * 03-27-92 DJM POSIX support.
  47. * 08-08-92 GJF Use seek method constants!
  48. * 08-26-92 GJF Include unistd.h for POSIX build.
  49. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  50. * 05-24-93 GJF If the stream was opened for read-access-only, reduce
  51. * _bufsiz after flushing the stream. This should reduce
  52. * the expense of the next _filbuf call, and the overall
  53. * burden of seek-and-do-small-reads patterns of file
  54. * input.
  55. * 06-22-93 GJF Check _flag for _IOSETVBUF (new) before changing
  56. * buffer size.
  57. * 11-05-93 GJF Merged with NT SDK version. Also, replaced MTHREAD
  58. * with _MT.
  59. * 02-06-94 CFW assert -> _ASSERTE.
  60. * 02-20-95 GJF Merged in Mac version.
  61. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
  62. * 03-02-98 GJF Exception-safe locking.
  63. * 05-17-99 PML Remove all Macintosh support.
  64. *
  65. *******************************************************************************/
  66. #include <cruntime.h>
  67. #include <stdio.h>
  68. #include <file2.h>
  69. #include <dbgint.h>
  70. #ifdef _POSIX_
  71. #include <unistd.h>
  72. #else
  73. #include <msdos.h>
  74. #endif
  75. #include <errno.h>
  76. #include <malloc.h>
  77. #include <io.h>
  78. #include <stddef.h>
  79. #include <internal.h>
  80. #ifndef _POSIX_
  81. #include <mtdll.h>
  82. #endif
  83. /***
  84. *int fseek(stream, offset, whence) - reposition file pointer
  85. *
  86. *Purpose:
  87. *
  88. * Reposition file pointer to the desired location. The new location
  89. * is calculated as follows:
  90. * { whence=0, beginning of file }
  91. * <offset> bytes + { whence=1, current position }
  92. * { whence=2, end of file }
  93. *
  94. * Be careful to coordinate with buffering.
  95. *
  96. * - - - - - - - - - - - - -
  97. *
  98. * [NOTE: We used to bend over backwards to try and preserve the current
  99. * buffer and maintain disk block alignment. This ended up making our
  100. * code big and slow and complicated, and slowed us down quite a bit.
  101. * Some of the things pertinent to the old implimentation:
  102. *
  103. * (1) Read-only: We only did the special code path if the file was
  104. * opened read-only (_IOREAD). If the file was writable, we didn't
  105. * try to optimize.
  106. *
  107. * (2) Buffering: We'd assign a buffer, if necessary, since the
  108. * later code might need it (i.e., call _getbuf).
  109. *
  110. * (3) Ungetc: Fseek had to be careful NOT to save the buffer if
  111. * an ungetc had ever been done on the buffer (flag _IOUNGETC).
  112. *
  113. * (4) Control ^Z: Fseek had to deal with ^Z after reading a
  114. * new buffer's worth of data (flag _IOCTRLZ).
  115. *
  116. * (5) Seek-to-end-and-back: To determine if the new seek was within
  117. * the current buffer, we had to 'normalize' the desired location.
  118. * This means that we sometimes had to seek to the end of the file
  119. * and back to determine what the 0-relative offset was. Two extra
  120. * lseek() calls hurt performance.
  121. *
  122. * (6) CR/LF accounting - When trying to seek within a buffer that
  123. * is in text mode, we had to go account for CR/LF expansion. This
  124. * required us to look at every character up to the new offset and
  125. * see if it was '\n' or not. In addition, we had to check the
  126. * FCRLF flag to see if the new buffer started with '\n'.
  127. *
  128. * Again, all of these notes are for the OLD implimentation just to
  129. * remind folks of some of the issues involving seeking within a buffer
  130. * and maintaining buffer alignment. As an aside, I think this may have
  131. * been a big win in the 'old days' on floppy-based systems but on newer
  132. * fast hard disks, the extra code/complexity overwhelmed any gain.
  133. *
  134. * - - - - - - - - - - - - -
  135. *
  136. *Entry:
  137. * FILE *stream - file to reposition file pointer on
  138. * long offset - offset to seek to
  139. * int whence - origin offset is measured from (0=beg, 1=current pos,
  140. * 2=end)
  141. *
  142. *Exit:
  143. * returns 0 if succeeds
  144. * returns -1 and sets errno if fails
  145. * fields of FILE struct will be changed
  146. *
  147. *Exceptions:
  148. *
  149. *******************************************************************************/
  150. #ifdef _MT /* multi-thread; define both fseek() and _lk_fseek() */
  151. int __cdecl fseek (
  152. FILE *stream,
  153. long offset,
  154. int whence
  155. )
  156. {
  157. int retval;
  158. _ASSERTE(stream != NULL);
  159. _lock_str(stream);
  160. __try {
  161. retval = _fseek_lk (stream, offset, whence);
  162. }
  163. __finally {
  164. _unlock_str(stream);
  165. }
  166. return(retval);
  167. }
  168. /***
  169. *_fseek_lk() - Core fseek() routine (stream is locked)
  170. *
  171. *Purpose:
  172. * Core fseek() routine; assumes that caller has the stream locked.
  173. *
  174. * [See fseek() for more info.]
  175. *
  176. *Entry: [See fseek()]
  177. *
  178. *Exit: [See fseek()]
  179. *
  180. *Exceptions:
  181. *
  182. *******************************************************************************/
  183. int __cdecl _fseek_lk (
  184. #else /* non multi-thread; just define fseek() */
  185. int __cdecl fseek (
  186. #endif /* rejoin common code */
  187. FILE *str,
  188. long offset,
  189. int whence
  190. )
  191. {
  192. REG1 FILE *stream;
  193. _ASSERTE(str != NULL);
  194. /* Init stream pointer */
  195. stream = str;
  196. if ( !inuse(stream) || ((whence != SEEK_SET) && (whence != SEEK_CUR) &&
  197. (whence != SEEK_END)) ) {
  198. errno=EINVAL;
  199. return(-1);
  200. }
  201. /* Clear EOF flag */
  202. stream->_flag &= ~_IOEOF;
  203. /* If seeking relative to current location, then convert to
  204. a seek relative to beginning of file. This accounts for
  205. buffering, etc. by letting fseek() tell us where we are. */
  206. if (whence == SEEK_CUR) {
  207. offset += _ftell_lk(stream);
  208. whence = SEEK_SET;
  209. }
  210. /* Flush buffer as necessary */
  211. #ifdef _POSIX_
  212. /*
  213. * If the stream was last read, we throw away the buffer so
  214. * that a possible subsequent write will encounter a clean
  215. * buffer. (The Win32 version of fflush() throws away the
  216. * buffer if it's read.) Write buffers must be flushed.
  217. */
  218. if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOREAD) {
  219. stream->_ptr = stream->_base;
  220. stream->_cnt = 0;
  221. } else {
  222. _flush(stream);
  223. }
  224. #else
  225. _flush(stream);
  226. #endif
  227. /* If file opened for read/write, clear flags since we don't know
  228. what the user is going to do next. If the file was opened for
  229. read access only, decrease _bufsiz so that the next _filbuf
  230. won't cost quite so much */
  231. if (stream->_flag & _IORW)
  232. stream->_flag &= ~(_IOWRT|_IOREAD);
  233. else if ( (stream->_flag & _IOREAD) && (stream->_flag & _IOMYBUF) &&
  234. !(stream->_flag & _IOSETVBUF) )
  235. stream->_bufsiz = _SMALL_BUFSIZ;
  236. /* Seek to the desired locale and return. */
  237. #ifdef _POSIX_
  238. return(lseek(fileno(stream), offset, whence) == -1L ? -1 : 0);
  239. #else
  240. return(_lseek(_fileno(stream), offset, whence) == -1L ? -1 : 0);
  241. #endif
  242. }