Leaked source code of windows server 2003
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.

221 lines
8.5 KiB

  1. /***
  2. *fwrite.c - read from a stream
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Write to the specified stream from the user's buffer.
  8. *
  9. *Revision History:
  10. * 06-23-89 PHG Module created, based on asm version
  11. * 01-18-90 GJF Must call _fflush_lk() rather than fflush().
  12. * 02-15-90 GJF _iob[], _iob2[] merge. Also, fixed copyright and
  13. * indents.
  14. * 03-19-90 GJF Made calling type _CALLTYPE1 and added #include
  15. * <cruntime.h>. Also, fixed compiler warning.
  16. * 05-29-90 SBM Use _flush, not [_]fflush[_lk]
  17. * 07-26-90 SBM Added #include <internal.h>
  18. * 08-14-90 SBM Compiles cleanly with -W3
  19. * 10-02-90 GJF New-style function declarators.
  20. * 01-22-91 GJF ANSI naming.
  21. * 03-27-92 DJM POSIX support.
  22. * 08-26-92 GJF Include unistd.h for POSIX build.
  23. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  24. * 05-11-93 GJF Replaced BUFSIZ with _INTERNAL_BUFSIZ.
  25. * 10-22-93 GJF Fix divide-by-0 error in unbuffered case. Also,
  26. * replaced MTHREAD with _MT.
  27. * 12-30-94 GJF _MAC_ merge.
  28. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
  29. * 05-24-95 CFW Return 0 if none to write.
  30. * 03-02-98 GJF Exception-safe locking.
  31. * 01-04-99 GJF Changes for 64-bit size_t.
  32. * 05-17-99 PML Remove all Macintosh support.
  33. *
  34. *******************************************************************************/
  35. #include <cruntime.h>
  36. #ifdef _POSIX_
  37. #include <unistd.h>
  38. #endif
  39. #include <stdio.h>
  40. #include <mtdll.h>
  41. #include <io.h>
  42. #include <string.h>
  43. #include <file2.h>
  44. #include <internal.h>
  45. /***
  46. *size_t fwrite(void *buffer, size_t size, size_t count, FILE *stream) -
  47. * write to the specified stream from the specified buffer.
  48. *
  49. *Purpose:
  50. * Write 'count' items of size 'size' to the specified stream from
  51. * the specified buffer. Return when 'count' items have been written
  52. * or no more items can be written to the stream.
  53. *
  54. *Entry:
  55. * buffer - pointer to user's buffer
  56. * size - size of the item to write
  57. * count - number of items to write
  58. * stream - stream to write to
  59. *
  60. *Exit:
  61. * Returns the number of (whole) items that were written to the stream.
  62. * This may be less than 'count' if an error or eof occurred. In this
  63. * case, ferror() or feof() should be used to distinguish between the
  64. * two conditions.
  65. *
  66. *Notes:
  67. * fwrite will attempt to buffer the stream (side effect of the _flsbuf
  68. * call) if necessary.
  69. *
  70. * No more than 0xFFFE bytes may be written out at a time by a call to
  71. * write(). Further, write() does not handle huge buffers. Therefore,
  72. * in large data models, the write request is broken down into chunks
  73. * that do not violate these considerations. Each of these chunks is
  74. * processed much like an fwrite() call in a small data model (by a
  75. * call to _nfwrite()).
  76. *
  77. * This code depends on _iob[] being a near array.
  78. *
  79. * MTHREAD/DLL - Handled in just two layers since it is small data
  80. * model. The outer layer, fwrite(), handles stream locking/unlocking
  81. * and calls _fwrite_lk() to do the work. _fwrite_lk() is the same as
  82. * the single-thread, small data model version of fwrite().
  83. *
  84. *******************************************************************************/
  85. #ifdef _MT
  86. /* define locking/unlocking version */
  87. size_t __cdecl fwrite (
  88. const void *buffer,
  89. size_t size,
  90. size_t count,
  91. FILE *stream
  92. )
  93. {
  94. size_t retval;
  95. _lock_str(stream); /* lock stream */
  96. __try {
  97. /* do the read */
  98. retval = _fwrite_lk(buffer, size, count, stream);
  99. }
  100. __finally {
  101. _unlock_str(stream); /* unlock stream */
  102. }
  103. return retval;
  104. }
  105. #endif
  106. /* define the normal version */
  107. #ifdef _MT
  108. size_t __cdecl _fwrite_lk (
  109. #else
  110. size_t __cdecl fwrite (
  111. #endif
  112. const void *buffer,
  113. size_t size,
  114. size_t num,
  115. FILE *stream
  116. )
  117. {
  118. const char *data; /* point to where data comes from next */
  119. size_t total; /* total bytes to write */
  120. size_t count; /* num bytes left to write */
  121. unsigned bufsize; /* size of stream buffer */
  122. unsigned nbytes; /* number of bytes to write now */
  123. unsigned nwritten; /* number of bytes written */
  124. int c; /* a temp char */
  125. /* initialize local vars */
  126. data = buffer;
  127. count = total = size * num;
  128. if (0 == count)
  129. return 0;
  130. if (anybuf(stream))
  131. /* already has buffer, use its size */
  132. bufsize = stream->_bufsiz;
  133. else
  134. /* assume will get _INTERNAL_BUFSIZ buffer */
  135. bufsize = _INTERNAL_BUFSIZ;
  136. /* here is the main loop -- we go through here until we're done */
  137. while (count != 0) {
  138. /* if the buffer is big and has room, copy data to buffer */
  139. if (bigbuf(stream) && stream->_cnt != 0) {
  140. /* how much do we want? */
  141. nbytes = (count < (unsigned)stream->_cnt) ? (unsigned)count : stream->_cnt;
  142. memcpy(stream->_ptr, data, nbytes);
  143. /* update stream and amt of data written */
  144. count -= nbytes;
  145. stream->_cnt -= nbytes;
  146. stream->_ptr += nbytes;
  147. data += nbytes;
  148. }
  149. else if (count >= bufsize) {
  150. /* If we have more than bufsize chars to write, write
  151. data by calling write with an integral number of
  152. bufsiz blocks. If we reach here and we have a big
  153. buffer, it must be full so _flush it. */
  154. if (bigbuf(stream)) {
  155. if (_flush(stream)) {
  156. /* error, stream flags set -- we're out
  157. of here */
  158. return (total - count) / size;
  159. }
  160. }
  161. /* calc chars to read -- (count/bufsize) * bufsize */
  162. nbytes = ( bufsize ? (unsigned)(count - count % bufsize) :
  163. (unsigned)count );
  164. #ifdef _POSIX_
  165. nwritten = write(fileno(stream), data, nbytes);
  166. #else
  167. nwritten = _write(_fileno(stream), data, nbytes);
  168. #endif
  169. if (nwritten == (unsigned)EOF) {
  170. /* error -- out of here */
  171. stream->_flag |= _IOERR;
  172. return (total - count) / size;
  173. }
  174. /* update count and data to reflect write */
  175. count -= nwritten;
  176. data += nwritten;
  177. if (nwritten < nbytes) {
  178. /* error -- out of here */
  179. stream->_flag |= _IOERR;
  180. return (total - count) / size;
  181. }
  182. }
  183. else {
  184. /* buffer full and not enough chars to do direct write,
  185. so do a _flsbuf. */
  186. c = *data; /* _flsbuf write one char, this is it */
  187. if (_flsbuf(c, stream) == EOF) {
  188. /* error or eof, stream flags set by _flsbuf */
  189. return (total - count) / size;
  190. }
  191. /* _flsbuf wrote a char -- update count */
  192. ++data;
  193. --count;
  194. /* update buffer size */
  195. bufsize = stream->_bufsiz > 0 ? stream->_bufsiz : 1;
  196. }
  197. }
  198. /* we finished successfully, so just return num */
  199. return num;
  200. }