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.

401 lines
12 KiB

  1. /***
  2. *fflush.c - flush a stream buffer
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines fflush() - flush the buffer on a stream
  8. * _flushall() - flush all stream buffers
  9. *
  10. *Revision History:
  11. * 09-01-83 RN initial version
  12. * 11-02-87 JCR Multi-thread support
  13. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  14. * 01-13-88 JCR Removed unnecessary calls to mthread fileno/feof/ferror
  15. * 05-27-88 PHG Merge DLL and normal versions
  16. * 06-14-88 JCR Use near pointer to reference _iob[] entries
  17. * 08-24-88 GJF Don't use FP_OFF() macro for the 386
  18. * 08-17-89 GJF Clean up, now specific to OS/2 2.0 (i.e., 386 flat
  19. * model). Also fixed copyright and indents.
  20. * 11-29-89 GJF Added support for fflush(NULL) (per ANSI). Merged in
  21. * flushall().
  22. * 01-24-90 GJF Fixed fflush(NULL) functionality to comply with ANSI
  23. * (must only call fflush() for output streams)
  24. * 03-16-90 GJF Made calling type _CALLTYPE1, added #include
  25. * <cruntime.h> and removed #include <register.h>.
  26. * 03-26-90 GJF Made flsall() _CALLTYPE4.
  27. * 05-09-90 SBM _fflush_lk became _flush, added new [_]fflush[_lk]
  28. * 07-11-90 SBM Commit mode on a per stream basis
  29. * 10-02-90 GJF New-style function declarators.
  30. * 12-12-90 GJF Fixed mis-placed paran in ternary expr commiting the
  31. * buffers.
  32. * 01-16-91 SRW Reversed test of _commit return value
  33. * 01-21-91 GJF ANSI naming.
  34. * 06-05-91 GJF On a successful _flush of a read/write stream in write
  35. * mode, clear _IOWRT so that the next operation can be a
  36. * read. ANSI requirement (C700 bug #2531).
  37. * 07-30-91 GJF Added support for termination scheme used on
  38. * non-Cruiser targets [_WIN32_].
  39. * 08-19-91 JCR Added _exitflag, _endstdio
  40. * 03-16-92 SKS Moved _cflush to the initializer module (in assembler)
  41. * 03-27-92 DJM POSIX support.
  42. * 08-26-92 GJF Include unistd.h for POSIX build.
  43. * 03-18-93 CFW fflush_lk returns 0 before exit.
  44. * 03-19-93 GJF Revised flsall() so that, in multi-thread models,
  45. * unused streams are not locked unnecessarily.
  46. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  47. * 05-10-93 GJF Purged ftell call accidently checked in 3/10/93.
  48. * 10-29-93 GJF Define entry for termination section (used to be in
  49. * in i386\cinitstd.asm). Also, replaced MTHREAD with
  50. * _MT.
  51. * 04-05-94 GJF #ifdef-ed out _cflush definition for msvcrt*.dll, it
  52. * is unnecessary.
  53. * 08-18-94 GJF Moved terminator stuff (including _cflush def) to
  54. * _file.c
  55. * 02-17-95 GJF Appended Mac version of source file (somewhat cleaned
  56. * up), with appropriate #ifdef-s.
  57. * 03-07-95 GJF Changed flsall() to iterate over the __piob[] table.
  58. * Also, changed to locks based on __piob.
  59. * 12-28-95 GJF Repaced reference to _NSTREAM_ with _nstream (users
  60. * may change the max. number of supported streams).
  61. * 08-01-96 RDK Change termination pointer data type to static.
  62. * 02-13-98 GJF Changes for Win64: added int cast to pointer diff.
  63. * 02-27-98 GJF Exception-safe locking.
  64. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  65. * 05-17-99 PML Remove all Macintosh support.
  66. *
  67. *******************************************************************************/
  68. #include <sect_attribs.h>
  69. #include <cruntime.h>
  70. #ifdef _POSIX_
  71. #include <unistd.h>
  72. #include <fcntl.h>
  73. #endif
  74. #include <stdio.h>
  75. #include <file2.h>
  76. #include <io.h>
  77. #include <mtdll.h>
  78. #include <internal.h>
  79. /* Values passed to flsall() to distinguish between _flushall() and
  80. * fflush(NULL) behavior
  81. */
  82. #define FLUSHALL 1
  83. #define FFLUSHNULL 0
  84. /* Core routine for fflush(NULL) and flushall()
  85. */
  86. static int __cdecl flsall(int);
  87. /***
  88. *int fflush(stream) - flush the buffer on a stream
  89. *
  90. *Purpose:
  91. * if file open for writing and buffered, flush the buffer. if problems
  92. * flushing the buffer, set the stream flag to error
  93. * Always flushes the stdio stream and forces a commit to disk if file
  94. * was opened in commit mode.
  95. *
  96. *Entry:
  97. * FILE *stream - stream to flush
  98. *
  99. *Exit:
  100. * returns 0 if flushed successfully, or no buffer to flush
  101. * returns EOF and sets file error flag if fails.
  102. * FILE struct entries affected: _ptr, _cnt, _flag.
  103. *
  104. *Exceptions:
  105. *
  106. *******************************************************************************/
  107. #ifdef _MT
  108. int __cdecl fflush (
  109. REG1 FILE *stream
  110. )
  111. {
  112. int rc;
  113. /* if stream is NULL, flush all streams
  114. */
  115. if ( stream == NULL )
  116. return(flsall(FFLUSHNULL));
  117. _lock_str(stream);
  118. __try {
  119. rc = _fflush_lk(stream);
  120. }
  121. __finally {
  122. _unlock_str(stream);
  123. }
  124. return(rc);
  125. }
  126. /***
  127. *_fflush_lk() - Flush the buffer on a stream (stream is already locked)
  128. *
  129. *Purpose:
  130. * Core flush routine; assumes stream lock is held by caller.
  131. *
  132. * [See fflush() above for more information.]
  133. *
  134. *Entry:
  135. * [See fflush()]
  136. *Exit:
  137. * [See fflush()]
  138. *
  139. *Exceptions:
  140. *
  141. *******************************************************************************/
  142. int __cdecl _fflush_lk (
  143. REG1 FILE *str
  144. )
  145. {
  146. #else /* non multi-thread */
  147. int __cdecl fflush (
  148. REG1 FILE *str
  149. )
  150. {
  151. /* if stream is NULL, flush all streams */
  152. if ( str == NULL ) {
  153. return(flsall(FFLUSHNULL));
  154. }
  155. #endif /* rejoin common code */
  156. if (_flush(str) != 0) {
  157. /* _flush failed, don't attempt to commit */
  158. return(EOF);
  159. }
  160. /* lowio commit to ensure data is written to disk */
  161. #ifndef _POSIX_
  162. if (str->_flag & _IOCOMMIT) {
  163. return (_commit(_fileno(str)) ? EOF : 0);
  164. }
  165. #endif
  166. return 0;
  167. }
  168. /***
  169. *int _flush(stream) - flush the buffer on a single stream
  170. *
  171. *Purpose:
  172. * If file open for writing and buffered, flush the buffer. If
  173. * problems flushing the buffer, set the stream flag to error.
  174. * Multi-thread version assumes stream lock is held by caller.
  175. *
  176. *Entry:
  177. * FILE* stream - stream to flush
  178. *
  179. *Exit:
  180. * Returns 0 if flushed successfully, or if no buffer to flush.,
  181. * Returns EOF and sets file error flag if fails.
  182. * File struct entries affected: _ptr, _cnt, _flag.
  183. *
  184. *Exceptions:
  185. *
  186. *******************************************************************************/
  187. int __cdecl _flush (
  188. FILE *str
  189. )
  190. {
  191. REG1 FILE *stream;
  192. REG2 int rc = 0; /* assume good return */
  193. REG3 int nchar;
  194. /* Init pointer to stream */
  195. stream = str;
  196. #ifdef _POSIX_
  197. /*
  198. * Insure that EBADF is returned whenever the underlying
  199. * file descriptor is closed.
  200. */
  201. if (-1 == fcntl(fileno(stream), F_GETFL))
  202. return(EOF);
  203. /*
  204. * Posix ignores read streams to insure that the result of
  205. * ftell() is the same before and after fflush(), and to
  206. * avoid seeking on pipes, ttys, etc.
  207. */
  208. if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOREAD) {
  209. return 0;
  210. }
  211. #endif /* _POSIX_ */
  212. if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream)
  213. && (nchar = (int)(stream->_ptr - stream->_base)) > 0)
  214. {
  215. #ifdef _POSIX_
  216. if ( write(fileno(stream), stream->_base, nchar) == nchar ) {
  217. #else
  218. if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) {
  219. #endif
  220. /* if this is a read/write file, clear _IOWRT so that
  221. * next operation can be a read
  222. */
  223. if ( _IORW & stream->_flag )
  224. stream->_flag &= ~_IOWRT;
  225. }
  226. else {
  227. stream->_flag |= _IOERR;
  228. rc = EOF;
  229. }
  230. }
  231. stream->_ptr = stream->_base;
  232. stream->_cnt = 0;
  233. return(rc);
  234. }
  235. /***
  236. *int _flushall() - flush all output buffers
  237. *
  238. *Purpose:
  239. * flushes all the output buffers to the file, clears all input buffers.
  240. *
  241. *Entry:
  242. * None.
  243. *
  244. *Exit:
  245. * returns number of open streams
  246. *
  247. *Exceptions:
  248. *
  249. *******************************************************************************/
  250. int __cdecl _flushall (
  251. void
  252. )
  253. {
  254. return(flsall(FLUSHALL));
  255. }
  256. /***
  257. *static int flsall(flushflag) - flush all output buffers
  258. *
  259. *Purpose:
  260. * Flushes all the output buffers to the file and, if FLUSHALL is passed,
  261. * clears all input buffers. Core routine for both fflush(NULL) and
  262. * flushall().
  263. *
  264. * MTHREAD Note: All the locking/unlocking required for both fflush(NULL)
  265. * and flushall() is performed in this routine.
  266. *
  267. *Entry:
  268. * int flushflag - flag indicating the exact semantics, there are two
  269. * legal values: FLUSHALL and FFLUSHNULL
  270. *
  271. *Exit:
  272. * if flushflag == FFLUSHNULL then flsbuf returns:
  273. 0, if successful
  274. * EOF, if an error occurs while flushing one of the streams
  275. *
  276. * if flushflag == FLUSHALL then flsbuf returns the number of streams
  277. * successfully flushed
  278. *
  279. *Exceptions:
  280. *
  281. *******************************************************************************/
  282. static int __cdecl flsall (
  283. int flushflag
  284. )
  285. {
  286. REG1 int i;
  287. int count = 0;
  288. int errcode = 0;
  289. #ifdef _MT
  290. _mlock(_IOB_SCAN_LOCK);
  291. __try {
  292. #endif
  293. for ( i = 0 ; i < _nstream ; i++ ) {
  294. if ( (__piob[i] != NULL) && (inuse((FILE *)__piob[i])) ) {
  295. #ifdef _MT
  296. /*
  297. * lock the stream. this is not done until testing
  298. * the stream is in use to avoid unnecessarily creating
  299. * a lock for every stream. the price is having to
  300. * retest the stream after the lock has been asserted.
  301. */
  302. _lock_str2(i, __piob[i]);
  303. __try {
  304. /*
  305. * if the stream is STILL in use (it may have been
  306. * closed before the lock was asserted), see about
  307. * flushing it.
  308. */
  309. if ( inuse((FILE *)__piob[i]) ) {
  310. #endif
  311. if ( flushflag == FLUSHALL ) {
  312. /*
  313. * FLUSHALL functionality: fflush the read or
  314. * write stream and, if successful, update the
  315. * count of flushed streams
  316. */
  317. if ( _fflush_lk(__piob[i]) != EOF )
  318. /* update count of successfully flushed
  319. * streams
  320. */
  321. count++;
  322. }
  323. else if ( (flushflag == FFLUSHNULL) &&
  324. (((FILE *)__piob[i])->_flag & _IOWRT) ) {
  325. /*
  326. * FFLUSHNULL functionality: fflush the write
  327. * stream and kept track of the error, if one
  328. * occurs
  329. */
  330. if ( _fflush_lk(__piob[i]) == EOF )
  331. errcode = EOF;
  332. }
  333. #ifdef _MT
  334. }
  335. }
  336. __finally {
  337. _unlock_str2(i, __piob[i]);
  338. }
  339. #endif
  340. }
  341. }
  342. #ifdef _MT
  343. }
  344. __finally {
  345. _munlock(_IOB_SCAN_LOCK);
  346. }
  347. #endif
  348. if ( flushflag == FLUSHALL )
  349. return(count);
  350. else
  351. return(errcode);
  352. }