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.

324 lines
12 KiB

  1. /***
  2. *read.c - read from a file handle
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _read() - read from a file handle
  8. *
  9. *Revision History:
  10. * 06-19-89 PHG Module created, based on asm version
  11. * 03-13-90 GJF Made calling type _CALLTYPE2 (for now), added #include
  12. * <cruntime.h> and fixed compiler warnings. Also, fixed
  13. * the copyright.
  14. * 04-03-90 GJF Now _CALLTYPE1.
  15. * 07-24-90 SBM Removed '32' from API names
  16. * 08-14-90 SBM Compiles cleanly with -W3
  17. * 10-01-90 GJF New-style function declarator.
  18. * 12-04-90 GJF Appended Win32 version onto the source with #ifdef-s.
  19. * It is enough different that there is little point in
  20. * trying to more closely merge the two versions.
  21. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  22. * 12-06-90 SRW Changed to use _osfile and _osfhnd instead of _osfinfo
  23. * 12-28-90 SRW Added cast of void * to char * for Mips C Compiler
  24. * 01-16-91 GJF ANSI naming.
  25. * 01-29-91 SRW Changed to not read ahead on char devices [_WIN32_]
  26. * 02-01-91 SRW Changed to use ERROR_HANDLE_EOF error code (_WIN32_)
  27. * 02-25-91 MHL Adapt to ReadFile/WriteFile changes (_WIN32_)
  28. * 04-09-91 PNT Added _MAC_ conditional
  29. * 04-16-91 SRW Character device bug fix [_WIN32_]
  30. * 05-23-91 GJF Don't set FEOFLAG if handle corresponds to a device.
  31. * 10-24-91 GJF Added LPDWORD casts to make MIPS compiler happy.
  32. * ASSUMES THAT sizeof(int) == sizeof(DWORD).
  33. * 02-13-92 GJF Replaced _nfile by _nhandle for Win32.
  34. * 06-16-92 GJF Bug fix - if CR was the very last char read, and the
  35. * last char in the file, CRLF was getting written to
  36. * user's buffer.
  37. * 12-18-93 GJF Don't treat ERROR_BROKEN_PIPE as an error. Instead,
  38. * just return 0.
  39. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  40. * 08-10-94 GJF Don't check the caller's buffer for a LF if NOTHING
  41. * was actually read in!
  42. * 09-06-94 CFW Remove Cruiser support.
  43. * 09-06-94 CFW Replace MTHREAD with _MT.
  44. * 12-03-94 SKS Clean up OS/2 references
  45. * 01-04-95 GJF _WIN32_ -> _WIN32
  46. * 02-15-95 GJF Appended Mac version of source file (somewhat cleaned
  47. * up), with appropriate #ifdef-s.
  48. * 06-11-95 GJF Changed _osfile[], _osfhnd[] and _pipech[] to
  49. * _osfile(), _osfhnd() and _pipech(), which reference
  50. * __pioinfo[].
  51. * 06-27-95 GJF Added check that the file handle is open.
  52. * 07-09-96 GJF Replaced defined(_WIN32) with !defined(_MAC) and
  53. * defined(_M_M68K) || defined(_M_MPPC) with
  54. * defined(_MAC). Also, detab-ed and cleaned up the
  55. * format a bit.
  56. * 12-29-97 GJF Exception-safe locking.
  57. * 03-03-98 RKP Forced amount read to be int even with 64 bits
  58. * 05-17-99 PML Remove all Macintosh support.
  59. *
  60. *******************************************************************************/
  61. #include <cruntime.h>
  62. #include <oscalls.h>
  63. #include <mtdll.h>
  64. #include <io.h>
  65. #include <internal.h>
  66. #include <stdlib.h>
  67. #include <errno.h>
  68. #include <msdos.h>
  69. #define LF 10 /* line feed */
  70. #define CR 13 /* carriage return */
  71. #define CTRLZ 26 /* ctrl-z means eof for text */
  72. /***
  73. *int _read(fh, buf, cnt) - read bytes from a file handle
  74. *
  75. *Purpose:
  76. * Attempts to read cnt bytes from fh into a buffer.
  77. * If the file is in text mode, CR-LF's are mapped to LF's, thus
  78. * affecting the number of characters read. This does not
  79. * affect the file pointer.
  80. *
  81. * NOTE: The stdio _IOCTRLZ flag is tied to the use of FEOFLAG.
  82. * Cross-reference the two symbols before changing FEOFLAG's use.
  83. *
  84. *Entry:
  85. * int fh - file handle to read from
  86. * char *buf - buffer to read into
  87. * int cnt - number of bytes to read
  88. *
  89. *Exit:
  90. * Returns number of bytes read (may be less than the number requested
  91. * if the EOF was reached or the file is in text mode).
  92. * returns -1 (and sets errno) if fails.
  93. *
  94. *Exceptions:
  95. *
  96. *******************************************************************************/
  97. #ifdef _MT
  98. /* define normal version that locks/unlocks, validates fh */
  99. int __cdecl _read (
  100. int fh,
  101. void *buf,
  102. unsigned cnt
  103. )
  104. {
  105. int r; /* return value */
  106. /* validate handle */
  107. if ( ((unsigned)fh >= (unsigned)_nhandle) ||
  108. !(_osfile(fh) & FOPEN) )
  109. {
  110. /* out of range -- return error */
  111. errno = EBADF;
  112. _doserrno = 0; /* not o.s. error */
  113. return -1;
  114. }
  115. _lock_fh(fh); /* lock file */
  116. __try {
  117. if ( _osfile(fh) & FOPEN )
  118. r = _read_lk(fh, buf, cnt); /* read bytes */
  119. else {
  120. errno = EBADF;
  121. _doserrno = 0;
  122. r = -1;
  123. }
  124. }
  125. __finally {
  126. _unlock_fh(fh); /* unlock file */
  127. }
  128. return r;
  129. }
  130. /* now define version that doesn't lock/unlock, validate fh */
  131. int __cdecl _read_lk (
  132. int fh,
  133. void *buf,
  134. unsigned cnt
  135. )
  136. {
  137. int bytes_read; /* number of bytes read */
  138. char *buffer; /* buffer to read to */
  139. int os_read; /* bytes read on OS call */
  140. char *p, *q; /* pointers into buffer */
  141. char peekchr; /* peek-ahead character */
  142. ULONG filepos; /* file position after seek */
  143. ULONG dosretval; /* o.s. return value */
  144. #else
  145. /* now define normal version */
  146. int __cdecl _read (
  147. int fh,
  148. void *buf,
  149. unsigned cnt
  150. )
  151. {
  152. int bytes_read; /* number of bytes read */
  153. char *buffer; /* buffer to read to */
  154. int os_read; /* bytes read on OS call */
  155. char *p, *q; /* pointers into buffer */
  156. char peekchr; /* peek-ahead character */
  157. ULONG filepos; /* file position after seek */
  158. ULONG dosretval; /* o.s. return value */
  159. /* validate fh */
  160. if ( ((unsigned)fh >= (unsigned)_nhandle) ||
  161. !(_osfile(fh) & FOPEN) )
  162. {
  163. /* bad file handle */
  164. errno = EBADF;
  165. _doserrno = 0; /* not o.s. error */
  166. return -1;
  167. }
  168. #endif
  169. bytes_read = 0; /* nothing read yet */
  170. buffer = buf;
  171. if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
  172. /* nothing to read or at EOF, so return 0 read */
  173. return 0;
  174. }
  175. if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
  176. /* a pipe/device and pipe lookahead non-empty: read the lookahead
  177. * char */
  178. *buffer++ = _pipech(fh);
  179. ++bytes_read;
  180. --cnt;
  181. _pipech(fh) = LF; /* mark as empty */
  182. }
  183. /* read the data */
  184. if ( !ReadFile( (HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read,
  185. NULL ) )
  186. {
  187. /* ReadFile has reported an error. recognize two special cases.
  188. *
  189. * 1. map ERROR_ACCESS_DENIED to EBADF
  190. *
  191. * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
  192. * means the handle is a read-handle on a pipe for which
  193. * all write-handles have been closed and all data has been
  194. * read. */
  195. if ( (dosretval = GetLastError()) == ERROR_ACCESS_DENIED ) {
  196. /* wrong read/write mode should return EBADF, not EACCES */
  197. errno = EBADF;
  198. _doserrno = dosretval;
  199. return -1;
  200. }
  201. else if ( dosretval == ERROR_BROKEN_PIPE ) {
  202. return 0;
  203. }
  204. else {
  205. _dosmaperr(dosretval);
  206. return -1;
  207. }
  208. }
  209. bytes_read += os_read; /* update bytes read */
  210. if (_osfile(fh) & FTEXT) {
  211. /* now must translate CR-LFs to LFs in the buffer */
  212. /* set CRLF flag to indicate LF at beginning of buffer */
  213. if ( (os_read != 0) && (*(char *)buf == LF) )
  214. _osfile(fh) |= FCRLF;
  215. else
  216. _osfile(fh) &= ~FCRLF;
  217. /* convert chars in the buffer: p is src, q is dest */
  218. p = q = buf;
  219. while (p < (char *)buf + bytes_read) {
  220. if (*p == CTRLZ) {
  221. /* if fh is not a device, set ctrl-z flag */
  222. if ( !(_osfile(fh) & FDEV) )
  223. _osfile(fh) |= FEOFLAG;
  224. break; /* stop translating */
  225. }
  226. else if (*p != CR)
  227. *q++ = *p++;
  228. else {
  229. /* *p is CR, so must check next char for LF */
  230. if (p < (char *)buf + bytes_read - 1) {
  231. if (*(p+1) == LF) {
  232. p += 2;
  233. *q++ = LF; /* convert CR-LF to LF */
  234. }
  235. else
  236. *q++ = *p++; /* store char normally */
  237. }
  238. else {
  239. /* This is the hard part. We found a CR at end of
  240. buffer. We must peek ahead to see if next char
  241. is an LF. */
  242. ++p;
  243. dosretval = 0;
  244. if ( !ReadFile( (HANDLE)_osfhnd(fh), &peekchr, 1,
  245. (LPDWORD)&os_read, NULL ) )
  246. dosretval = GetLastError();
  247. if (dosretval != 0 || os_read == 0) {
  248. /* couldn't read ahead, store CR */
  249. *q++ = CR;
  250. }
  251. else {
  252. /* peekchr now has the extra character -- we now
  253. have several possibilities:
  254. 1. disk file and char is not LF; just seek back
  255. and copy CR
  256. 2. disk file and char is LF; seek back and
  257. discard CR
  258. 3. disk file, char is LF but this is a one-byte
  259. read: store LF, don't seek back
  260. 4. pipe/device and char is LF; store LF.
  261. 5. pipe/device and char isn't LF, store CR and
  262. put char in pipe lookahead buffer. */
  263. if (_osfile(fh) & (FDEV|FPIPE)) {
  264. /* non-seekable device */
  265. if (peekchr == LF)
  266. *q++ = LF;
  267. else {
  268. *q++ = CR;
  269. _pipech(fh) = peekchr;
  270. }
  271. }
  272. else {
  273. /* disk file */
  274. if (q == buf && peekchr == LF) {
  275. /* nothing read yet; must make some
  276. progress */
  277. *q++ = LF;
  278. }
  279. else {
  280. /* seek back */
  281. filepos = _lseek_lk(fh, -1, FILE_CURRENT);
  282. if (peekchr != LF)
  283. *q++ = CR;
  284. }
  285. }
  286. }
  287. }
  288. }
  289. }
  290. /* we now change bytes_read to reflect the true number of chars
  291. in the buffer */
  292. bytes_read = (int)(q - (char *)buf);
  293. }
  294. return bytes_read; /* and return */
  295. }