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