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  * and/or 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 <<fflush>>, <<fflush_unlocked>>---flush buffered file output
21 
22 INDEX
23 	fflush
24 INDEX
25 	fflush_unlocked
26 INDEX
27 	_fflush_r
28 INDEX
29 	_fflush_unlocked_r
30 
31 SYNOPSIS
32 	#include <stdio.h>
33 	int fflush(FILE *<[fp]>);
34 
35 	#define _BSD_SOURCE
36 	#include <stdio.h>
37 	int fflush_unlocked(FILE *<[fp]>);
38 
39 	#include <stdio.h>
40 	int fflush( FILE *<[fp]>);
41 
42 	#define _BSD_SOURCE
43 	#include <stdio.h>
44 	int fflush_unlocked( FILE *<[fp]>);
45 
46 DESCRIPTION
47 The <<stdio>> output functions can buffer output before delivering it
48 to the host system, in order to minimize the overhead of system calls.
49 
50 Use <<fflush>> to deliver any such pending output (for the file
51 or stream identified by <[fp]>) to the host system.
52 
53 If <[fp]> is <<NULL>>, <<fflush>> delivers pending output from all
54 open files.
55 
56 Additionally, if <[fp]> is a seekable input stream visiting a file
57 descriptor, set the position of the file descriptor to match next
58 unread byte, useful for obeying POSIX semantics when ending a process
59 without consuming all input from the stream.
60 
61 <<fflush_unlocked>> is a non-thread-safe version of <<fflush>>.
62 <<fflush_unlocked>> may only safely be used within a scope
63 protected by flockfile() (or ftrylockfile()) and funlockfile().  This
64 function may safely be used in a multi-threaded program if and only
65 if they are called while the invoking thread owns the (FILE *)
66 object, as is the case after a successful call to the flockfile() or
67 ftrylockfile() functions.  If threads are disabled, then
68 <<fflush_unlocked>> is equivalent to <<fflush>>.
69 
70 The alternate functions <<_fflush_r>> and <<_fflush_unlocked_r>> are
71 reentrant versions, where the extra argument <[reent]> is a pointer to
72 a reentrancy structure, and <[fp]> must not be NULL.
73 
74 RETURNS
75 <<fflush>> returns <<0>> unless it encounters a write error; in that
76 situation, it returns <<EOF>>.
77 
78 PORTABILITY
79 ANSI C requires <<fflush>>.  The behavior on input streams is only
80 specified by POSIX, and not all implementations follow POSIX rules.
81 
82 <<fflush_unlocked>> is a BSD extension also provided by GNU libc.
83 
84 No supporting OS subroutines are required.
85 */
86 
87 #define _DEFAULT_SOURCE
88 #include <_ansi.h>
89 #include <stdio.h>
90 #include <errno.h>
91 #include "local.h"
92 
93 #ifdef __IMPL_UNLOCKED__
94 #define _fflush_r _fflush_unlocked_r
95 #define fflush fflush_unlocked
96 #endif
97 
98 #ifndef __IMPL_UNLOCKED__
99 /* Flush a single file, or (if fp is NULL) all files.  */
100 
101 /* Core function which does not lock file pointer.  This gets called
102    directly from __srefill. */
103 int
_sflush(register FILE * fp)104 _sflush (
105        register FILE * fp)
106 {
107   register unsigned char *p;
108   register size_t n;
109   register ssize_t t;
110   short flags;
111 
112   flags = fp->_flags;
113   if ((flags & __SWR) == 0)
114     {
115 #ifdef _FSEEK_OPTIMIZATION
116       /* For a read stream, an fflush causes the next seek to be
117          unoptimized (i.e. forces a system-level seek).  This conforms
118          to the POSIX and SUSv3 standards.  */
119       fp->_flags |= __SNPT;
120 #endif
121 
122       /* For a seekable stream with buffered read characters, we will attempt
123          a seek to the current position now.  A subsequent read will then get
124          the next byte from the file rather than the buffer.  This conforms
125          to the POSIX and SUSv3 standards.  Note that the standards allow
126          this seek to be deferred until necessary, but we choose to do it here
127          to make the change simpler, more contained, and less likely
128          to miss a code scenario.  */
129       if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL)
130 	{
131 	  int tmp_errno;
132 #ifdef __LARGE64_FILES
133 	  _fpos64_t curoff;
134 #else
135 	  _fpos_t curoff;
136 #endif
137 
138 	  /* Save last errno and set errno to 0, so we can check if a device
139 	     returns with a valid position -1.  We restore the last errno if
140 	     no other error condition has been encountered. */
141 	  tmp_errno = _REENT_ERRNO(ptr);
142 	  _REENT_ERRNO(ptr) = 0;
143 	  /* Get the physical position we are at in the file.  */
144 	  if (fp->_flags & __SOFF)
145 	    curoff = fp->_offset;
146 	  else
147 	    {
148 	      /* We don't know current physical offset, so ask for it.
149 		 Only ESPIPE and EINVAL are ignorable.  */
150 #ifdef __LARGE64_FILES
151 	      if (fp->_flags & __SL64)
152 		curoff = fp->_seek64 (fp->_cookie, 0, SEEK_CUR);
153 	      else
154 #endif
155 		curoff = fp->_seek (fp->_cookie, 0, SEEK_CUR);
156 	      if (curoff == -1L && _REENT_ERRNO(ptr) != 0)
157 		{
158 		  int result = EOF;
159 		  if (_REENT_ERRNO(ptr) == ESPIPE || _REENT_ERRNO(ptr) == EINVAL)
160 		    {
161 		      result = 0;
162 		      _REENT_ERRNO(ptr) = tmp_errno;
163 		    }
164 		  else
165 		    fp->_flags |= __SERR;
166 		  return result;
167 		}
168             }
169           if (fp->_flags & __SRD)
170             {
171               /* Current offset is at end of buffer.  Compensate for
172                  characters not yet read.  */
173               curoff -= fp->_r;
174               if (HASUB (fp))
175                 curoff -= fp->_ur;
176             }
177 	  /* Now physically seek to after byte last read.  */
178 #ifdef __LARGE64_FILES
179 	  if (fp->_flags & __SL64)
180 	    curoff = fp->_seek64 (fp->_cookie, curoff, SEEK_SET);
181 	  else
182 #endif
183 	    curoff = fp->_seek (fp->_cookie, curoff, SEEK_SET);
184 	  if (curoff != -1 || _REENT_ERRNO(ptr) == 0
185 	      || _REENT_ERRNO(ptr) == ESPIPE || _REENT_ERRNO(ptr) == EINVAL)
186 	    {
187 	      /* Seek successful or ignorable error condition.
188 		 We can clear read buffer now.  */
189 #ifdef _FSEEK_OPTIMIZATION
190 	      fp->_flags &= ~__SNPT;
191 #endif
192 	      fp->_r = 0;
193 	      fp->_p = fp->_bf._base;
194 	      if ((fp->_flags & __SOFF) && (curoff != -1 || _REENT_ERRNO(ptr) == 0))
195 		fp->_offset = curoff;
196 	      _REENT_ERRNO(ptr) = tmp_errno;
197 	      if (HASUB (fp))
198 		FREEUB (ptr, fp);
199 	    }
200 	  else
201 	    {
202 	      fp->_flags |= __SERR;
203 	      return EOF;
204 	    }
205 	}
206       return 0;
207     }
208   if ((p = fp->_bf._base) == NULL)
209     {
210       /* Nothing to flush.  */
211       return 0;
212     }
213   n = fp->_p - p;		/* write this much */
214 
215   /*
216    * Set these immediately to avoid problems with longjmp
217    * and to allow exchange buffering (via setvbuf) in user
218    * write function.
219    */
220   fp->_p = p;
221   fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size;
222 
223   while (n > 0)
224     {
225       t = fp->_write (fp->_cookie, (char *) p, n);
226       if (t <= 0)
227 	{
228           fp->_flags |= __SERR;
229           return EOF;
230 	}
231       p += t;
232       n -= t;
233     }
234   return 0;
235 }
236 
237 #ifdef _STDIO_BSD_SEMANTICS
238 /* Called from cleanup_stdio().  At exit time, we don't need file locking,
239    and we don't want to move the underlying file pointer unless we're
240    writing. */
241 int
_sflushw(register FILE * fp)242 _sflushw (
243        register FILE *fp)
244 {
245   return (fp->_flags & __SWR) ?  _sflush ( fp) : 0;
246 }
247 #endif
248 
249 #endif /* __IMPL_UNLOCKED__ */
250 
251 int
fflush(register FILE * fp)252 fflush (register FILE * fp)
253 {
254   if (fp == NULL)
255     return _fwalk_sglue (fflush, &__sglue);
256 
257   int ret;
258 
259 #ifdef _REENT_SMALL
260   /* For REENT_SMALL platforms, it is possible we are being
261      called for the first time on a std stream.  This std
262      stream can belong to a reentrant struct that is not
263      _REENT.  If CHECK_INIT gets called below based on _REENT,
264      we will end up changing said file pointers to the equivalent
265      std stream off of _REENT.  This causes unexpected behavior if
266      there is any data to flush on the _REENT std stream.  There
267      are two alternatives to fix this:  1) make a reentrant fflush
268      or 2) simply recognize that this file has nothing to flush
269      and return immediately before performing a CHECK_INIT.  Choice
270      2 is implemented here due to its simplicity.  */
271   if (fp->_bf._base == NULL)
272     return 0;
273 #endif /* _REENT_SMALL  */
274 
275   CHECK_INIT (ptr, fp);
276 
277   if (!fp->_flags)
278     return 0;
279 
280   _newlib_flockfile_start (fp);
281   ret = _sflush ( fp);
282   _newlib_flockfile_end (fp);
283   return ret;
284 }
285