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 <stdio.h>
89 #include <errno.h>
90 #include "local.h"
91 
92 #ifdef __IMPL_UNLOCKED__
93 #define _fflush_r _fflush_unlocked_r
94 #define fflush fflush_unlocked
95 #endif
96 
97 #ifndef __IMPL_UNLOCKED__
98 /* Flush a single file, or (if fp is NULL) all files.  */
99 
100 /* Core function which does not lock file pointer.  This gets called
101    directly from __srefill. */
102 int
_sflush(register FILE * fp)103 _sflush (
104        register FILE * fp)
105 {
106   register unsigned char *p;
107   register size_t n;
108   register ssize_t t;
109   short flags;
110 
111   flags = fp->_flags;
112   if ((flags & __SWR) == 0)
113     {
114 #ifdef _FSEEK_OPTIMIZATION
115       /* For a read stream, an fflush causes the next seek to be
116          unoptimized (i.e. forces a system-level seek).  This conforms
117          to the POSIX and SUSv3 standards.  */
118       fp->_flags |= __SNPT;
119 #endif
120 
121       /* For a seekable stream with buffered read characters, we will attempt
122          a seek to the current position now.  A subsequent read will then get
123          the next byte from the file rather than the buffer.  This conforms
124          to the POSIX and SUSv3 standards.  Note that the standards allow
125          this seek to be deferred until necessary, but we choose to do it here
126          to make the change simpler, more contained, and less likely
127          to miss a code scenario.  */
128       if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL)
129 	{
130 	  int tmp_errno;
131 #ifdef __LARGE64_FILES
132 	  _fpos64_t curoff;
133 #else
134 	  _fpos_t curoff;
135 #endif
136 
137 	  /* Save last errno and set errno to 0, so we can check if a device
138 	     returns with a valid position -1.  We restore the last errno if
139 	     no other error condition has been encountered. */
140 	  tmp_errno = _REENT_ERRNO(ptr);
141 	  _REENT_ERRNO(ptr) = 0;
142 	  /* Get the physical position we are at in the file.  */
143 	  if (fp->_flags & __SOFF)
144 	    curoff = fp->_offset;
145 	  else
146 	    {
147 	      /* We don't know current physical offset, so ask for it.
148 		 Only ESPIPE and EINVAL are ignorable.  */
149 #ifdef __LARGE64_FILES
150 	      if (fp->_flags & __SL64)
151 		curoff = fp->_seek64 (fp->_cookie, 0, SEEK_CUR);
152 	      else
153 #endif
154 		curoff = fp->_seek (fp->_cookie, 0, SEEK_CUR);
155 	      if (curoff == -1L && _REENT_ERRNO(ptr) != 0)
156 		{
157 		  int result = EOF;
158 		  if (_REENT_ERRNO(ptr) == ESPIPE || _REENT_ERRNO(ptr) == EINVAL)
159 		    {
160 		      result = 0;
161 		      _REENT_ERRNO(ptr) = tmp_errno;
162 		    }
163 		  else
164 		    fp->_flags |= __SERR;
165 		  return result;
166 		}
167             }
168           if (fp->_flags & __SRD)
169             {
170               /* Current offset is at end of buffer.  Compensate for
171                  characters not yet read.  */
172               curoff -= fp->_r;
173               if (HASUB (fp))
174                 curoff -= fp->_ur;
175             }
176 	  /* Now physically seek to after byte last read.  */
177 #ifdef __LARGE64_FILES
178 	  if (fp->_flags & __SL64)
179 	    curoff = fp->_seek64 (fp->_cookie, curoff, SEEK_SET);
180 	  else
181 #endif
182 	    curoff = fp->_seek (fp->_cookie, curoff, SEEK_SET);
183 	  if (curoff != -1 || _REENT_ERRNO(ptr) == 0
184 	      || _REENT_ERRNO(ptr) == ESPIPE || _REENT_ERRNO(ptr) == EINVAL)
185 	    {
186 	      /* Seek successful or ignorable error condition.
187 		 We can clear read buffer now.  */
188 #ifdef _FSEEK_OPTIMIZATION
189 	      fp->_flags &= ~__SNPT;
190 #endif
191 	      fp->_r = 0;
192 	      fp->_p = fp->_bf._base;
193 	      if ((fp->_flags & __SOFF) && (curoff != -1 || _REENT_ERRNO(ptr) == 0))
194 		fp->_offset = curoff;
195 	      _REENT_ERRNO(ptr) = tmp_errno;
196 	      if (HASUB (fp))
197 		FREEUB (ptr, fp);
198 	    }
199 	  else
200 	    {
201 	      fp->_flags |= __SERR;
202 	      return EOF;
203 	    }
204 	}
205       return 0;
206     }
207   if ((p = fp->_bf._base) == NULL)
208     {
209       /* Nothing to flush.  */
210       return 0;
211     }
212   n = fp->_p - p;		/* write this much */
213 
214   /*
215    * Set these immediately to avoid problems with longjmp
216    * and to allow exchange buffering (via setvbuf) in user
217    * write function.
218    */
219   fp->_p = p;
220   fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size;
221 
222   while (n > 0)
223     {
224       t = fp->_write (fp->_cookie, (char *) p, n);
225       if (t <= 0)
226 	{
227           fp->_flags |= __SERR;
228           return EOF;
229 	}
230       p += t;
231       n -= t;
232     }
233   return 0;
234 }
235 
236 #ifdef _STDIO_BSD_SEMANTICS
237 /* Called from cleanup_stdio().  At exit time, we don't need file locking,
238    and we don't want to move the underlying file pointer unless we're
239    writing. */
240 int
_sflushw(register FILE * fp)241 _sflushw (
242        register FILE *fp)
243 {
244   return (fp->_flags & __SWR) ?  _sflush ( fp) : 0;
245 }
246 #endif
247 
248 #endif /* __IMPL_UNLOCKED__ */
249 
250 int
fflush(register FILE * fp)251 fflush (register FILE * fp)
252 {
253   if (fp == NULL)
254     return _fwalk_sglue (fflush, &__sglue);
255 
256   int ret;
257 
258 #ifdef _REENT_SMALL
259   /* For REENT_SMALL platforms, it is possible we are being
260      called for the first time on a std stream.  This std
261      stream can belong to a reentrant struct that is not
262      _REENT.  If CHECK_INIT gets called below based on _REENT,
263      we will end up changing said file pointers to the equivalent
264      std stream off of _REENT.  This causes unexpected behavior if
265      there is any data to flush on the _REENT std stream.  There
266      are two alternatives to fix this:  1) make a reentrant fflush
267      or 2) simply recognize that this file has nothing to flush
268      and return immediately before performing a CHECK_INIT.  Choice
269      2 is implemented here due to its simplicity.  */
270   if (fp->_bf._base == NULL)
271     return 0;
272 #endif /* _REENT_SMALL  */
273 
274   CHECK_INIT (ptr, fp);
275 
276   if (!fp->_flags)
277     return 0;
278 
279   _newlib_flockfile_start (fp);
280   ret = _sflush ( fp);
281   _newlib_flockfile_end (fp);
282   return ret;
283 }
284