include/string.h: Also redirect calls if not inlined in libpthread
[glibc.git] / libio / oldfileops.c
bloba268ece373b1fc2e5d515181fc02c72e9318f106
1 /* Copyright (C) 1993-2025 Free Software Foundation, Inc.
2 Copyright The GNU Toolchain Authors.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>.
19 As a special exception, if you link the code in this file with
20 files compiled with a GNU compiler to produce an executable,
21 that does not cause the resulting executable to be covered by
22 the GNU Lesser General Public License. This exception does not
23 however invalidate any other reasons why the executable file
24 might be covered by the GNU Lesser General Public License.
25 This exception applies to code released by its copyright holders
26 in files containing the exception. */
28 /* This is a compatibility file. If we don't build the libc with
29 versioning don't compile this file. */
30 #include <shlib-compat.h>
31 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
33 #define _IO_USE_OLD_IO_FILE
34 #include "libioP.h"
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <unistd.h>
43 /* An fstream can be in at most one of put mode, get mode, or putback mode.
44 Putback mode is a variant of get mode.
46 In a filebuf, there is only one current position, instead of two
47 separate get and put pointers. In get mode, the current position
48 is that of gptr(); in put mode that of pptr().
50 The position in the buffer that corresponds to the position
51 in external file system is normally _IO_read_end, except in putback
52 mode, when it is _IO_save_end.
53 If the field _fb._offset is >= 0, it gives the offset in
54 the file as a whole corresponding to eGptr(). (?)
56 PUT MODE:
57 If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
58 and _IO_read_base are equal to each other. These are usually equal
59 to _IO_buf_base, though not necessarily if we have switched from
60 get mode to put mode. (The reason is to maintain the invariant
61 that _IO_read_end corresponds to the external file position.)
62 _IO_write_base is non-NULL and usually equal to _IO_buf_base.
63 We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
64 The un-flushed character are those between _IO_write_base and _IO_write_ptr.
66 GET MODE:
67 If a filebuf is in get or putback mode, eback() != egptr().
68 In get mode, the unread characters are between gptr() and egptr().
69 The OS file position corresponds to that of egptr().
71 PUTBACK MODE:
72 Putback mode is used to remember "excess" characters that have
73 been sputbackc'd in a separate putback buffer.
74 In putback mode, the get buffer points to the special putback buffer.
75 The unread characters are the characters between gptr() and egptr()
76 in the putback buffer, as well as the area between save_gptr()
77 and save_egptr(), which point into the original reserve buffer.
78 (The pointers save_gptr() and save_egptr() are the values
79 of gptr() and egptr() at the time putback mode was entered.)
80 The OS position corresponds to that of save_egptr().
82 LINE BUFFERED OUTPUT:
83 During line buffered output, _IO_write_base==base() && epptr()==base().
84 However, ptr() may be anywhere between base() and ebuf().
85 This forces a call to filebuf::overflow(int C) on every put.
86 If there is more space in the buffer, and C is not a '\n',
87 then C is inserted, and pptr() incremented.
89 UNBUFFERED STREAMS:
90 If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
93 #define CLOSED_FILEBUF_FLAGS \
94 (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
97 void
98 attribute_compat_text_section
99 _IO_old_file_init_internal (struct _IO_FILE_plus *fp)
101 /* POSIX.1 allows another file handle to be used to change the position
102 of our file descriptor. Hence we actually don't know the actual
103 position before we do the first fseek (and until a following fflush). */
104 fp->file._old_offset = _IO_pos_BAD;
105 fp->file._flags |= CLOSED_FILEBUF_FLAGS;
107 /* NB: _vtable_offset must be set before calling _IO_link_in since
108 _IO_vtable_offset is used to detect the old binaries. */
109 fp->file._vtable_offset = ((int) sizeof (struct _IO_FILE)
110 - (int) sizeof (struct _IO_FILE_complete));
111 _IO_link_in (fp);
112 fp->file._fileno = -1;
114 if (&_IO_stdin_used != NULL || !_IO_legacy_file ((FILE *) fp))
115 /* The object is dynamically allocated and large enough. Initialize
116 the _mode element as well. */
117 ((struct _IO_FILE_complete *) fp)->_mode = -1;
120 void
121 attribute_compat_text_section
122 _IO_old_file_init (struct _IO_FILE_plus *fp)
124 IO_set_accept_foreign_vtables (&_IO_vtable_check);
125 _IO_old_file_init_internal (fp);
129 attribute_compat_text_section
130 _IO_old_file_close_it (FILE *fp)
132 int write_status, close_status;
133 if (!_IO_file_is_open (fp))
134 return EOF;
136 write_status = _IO_old_do_flush (fp);
138 _IO_unsave_markers (fp);
140 close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0
141 ? _IO_SYSCLOSE (fp) : 0);
143 /* Free buffer. */
144 _IO_setb (fp, NULL, NULL, 0);
145 _IO_setg (fp, NULL, NULL, NULL);
146 _IO_setp (fp, NULL, NULL);
148 _IO_un_link ((struct _IO_FILE_plus *) fp);
149 fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
150 fp->_fileno = -1;
151 fp->_old_offset = _IO_pos_BAD;
153 return close_status ? close_status : write_status;
156 void
157 attribute_compat_text_section
158 _IO_old_file_finish (FILE *fp, int dummy)
160 if (_IO_file_is_open (fp))
162 _IO_old_do_flush (fp);
163 if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
164 _IO_SYSCLOSE (fp);
166 _IO_default_finish (fp, 0);
169 FILE *
170 attribute_compat_text_section
171 _IO_old_file_fopen (FILE *fp, const char *filename, const char *mode)
173 int oflags = 0, omode;
174 int read_write, fdesc;
175 int oprot = 0666;
176 if (_IO_file_is_open (fp))
177 return 0;
178 switch (*mode++)
180 case 'r':
181 omode = O_RDONLY;
182 read_write = _IO_NO_WRITES;
183 break;
184 case 'w':
185 omode = O_WRONLY;
186 oflags = O_CREAT|O_TRUNC;
187 read_write = _IO_NO_READS;
188 break;
189 case 'a':
190 omode = O_WRONLY;
191 oflags = O_CREAT|O_APPEND;
192 read_write = _IO_NO_READS|_IO_IS_APPENDING;
193 break;
194 default:
195 __set_errno (EINVAL);
196 return NULL;
198 if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
200 omode = O_RDWR;
201 read_write &= _IO_IS_APPENDING;
203 fdesc = __open (filename, omode|oflags, oprot);
204 if (fdesc < 0)
205 return NULL;
206 fp->_fileno = fdesc;
207 _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
208 if (read_write & _IO_IS_APPENDING)
209 if (_IO_SEEKOFF (fp, (off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
210 == _IO_pos_BAD && errno != ESPIPE)
211 return NULL;
212 _IO_link_in ((struct _IO_FILE_plus *) fp);
213 return fp;
216 FILE *
217 attribute_compat_text_section
218 _IO_old_file_attach (FILE *fp, int fd)
220 if (_IO_file_is_open (fp))
221 return NULL;
222 fp->_fileno = fd;
223 fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
224 fp->_flags |= _IO_DELETE_DONT_CLOSE;
225 /* Get the current position of the file. */
226 /* We have to do that since that may be junk. */
227 fp->_old_offset = _IO_pos_BAD;
228 if (_IO_SEEKOFF (fp, (off_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
229 == _IO_pos_BAD && errno != ESPIPE)
230 return NULL;
231 return fp;
234 FILE *
235 attribute_compat_text_section
236 _IO_old_file_setbuf (FILE *fp, char *p, ssize_t len)
238 if (_IO_default_setbuf (fp, p, len) == NULL)
239 return NULL;
241 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
242 = fp->_IO_buf_base;
243 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
245 return fp;
248 static int old_do_write (FILE *, const char *, size_t);
250 /* Write TO_DO bytes from DATA to FP.
251 Then mark FP as having empty buffers. */
254 attribute_compat_text_section
255 _IO_old_do_write (FILE *fp, const char *data, size_t to_do)
257 return (to_do == 0 || (size_t) old_do_write (fp, data, to_do) == to_do)
258 ? 0 : EOF;
261 static int
262 attribute_compat_text_section
263 old_do_write (FILE *fp, const char *data, size_t to_do)
265 size_t count;
266 if (fp->_flags & _IO_IS_APPENDING)
267 /* On a system without a proper O_APPEND implementation,
268 you would need to sys_seek(0, SEEK_END) here, but is
269 not needed nor desirable for Unix- or Posix-like systems.
270 Instead, just indicate that offset (before and after) is
271 unpredictable. */
272 fp->_old_offset = _IO_pos_BAD;
273 else if (fp->_IO_read_end != fp->_IO_write_base)
275 off_t new_pos
276 = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
277 if (new_pos == _IO_pos_BAD)
278 return 0;
279 fp->_old_offset = new_pos;
281 count = _IO_SYSWRITE (fp, data, to_do);
282 if (fp->_cur_column && count)
283 fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
284 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
285 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
286 fp->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
287 ? fp->_IO_buf_base : fp->_IO_buf_end);
288 return count;
292 attribute_compat_text_section
293 _IO_old_file_underflow (FILE *fp)
295 ssize_t count;
297 /* C99 requires EOF to be "sticky". */
298 if (fp->_flags & _IO_EOF_SEEN)
299 return EOF;
301 if (fp->_flags & _IO_NO_READS)
303 fp->_flags |= _IO_ERR_SEEN;
304 __set_errno (EBADF);
305 return EOF;
307 if (fp->_IO_read_ptr < fp->_IO_read_end)
308 return *(unsigned char *) fp->_IO_read_ptr;
310 if (fp->_IO_buf_base == NULL)
312 /* Maybe we already have a push back pointer. */
313 if (fp->_IO_save_base != NULL)
315 _IO_free_backup_buf (fp, fp->_IO_save_base);
316 fp->_flags &= ~_IO_IN_BACKUP;
318 _IO_doallocbuf (fp);
321 /* Flush all line buffered files before reading. */
322 /* FIXME This can/should be moved to genops ?? */
323 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
324 _IO_flush_all_linebuffered ();
326 _IO_switch_to_get_mode (fp);
328 /* This is very tricky. We have to adjust those
329 pointers before we call _IO_SYSREAD () since
330 we may longjump () out while waiting for
331 input. Those pointers may be screwed up. H.J. */
332 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
333 fp->_IO_read_end = fp->_IO_buf_base;
334 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
335 = fp->_IO_buf_base;
337 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
338 fp->_IO_buf_end - fp->_IO_buf_base);
339 if (count <= 0)
341 if (count == 0)
342 fp->_flags |= _IO_EOF_SEEN;
343 else
344 fp->_flags |= _IO_ERR_SEEN, count = 0;
346 fp->_IO_read_end += count;
347 if (count == 0)
348 return EOF;
349 if (fp->_old_offset != _IO_pos_BAD)
350 _IO_pos_adjust (fp->_old_offset, count);
351 return *(unsigned char *) fp->_IO_read_ptr;
355 attribute_compat_text_section
356 _IO_old_file_overflow (FILE *f, int ch)
358 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
360 f->_flags |= _IO_ERR_SEEN;
361 __set_errno (EBADF);
362 return EOF;
364 /* If currently reading or no buffer allocated. */
365 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
367 /* Allocate a buffer if needed. */
368 if (f->_IO_write_base == 0)
370 _IO_doallocbuf (f);
371 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
373 /* Otherwise must be currently reading.
374 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
375 logically slide the buffer forwards one block (by setting the
376 read pointers to all point at the beginning of the block). This
377 makes room for subsequent output.
378 Otherwise, set the read pointers to _IO_read_end (leaving that
379 alone, so it can continue to correspond to the external position). */
380 if (f->_IO_read_ptr == f->_IO_buf_end)
381 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
382 f->_IO_write_ptr = f->_IO_read_ptr;
383 f->_IO_write_base = f->_IO_write_ptr;
384 f->_IO_write_end = f->_IO_buf_end;
385 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
387 if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
388 f->_IO_write_end = f->_IO_write_ptr;
389 f->_flags |= _IO_CURRENTLY_PUTTING;
391 if (ch == EOF)
392 return _IO_old_do_flush (f);
393 if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
394 if (_IO_old_do_flush (f) == EOF)
395 return EOF;
396 *f->_IO_write_ptr++ = ch;
397 if ((f->_flags & _IO_UNBUFFERED)
398 || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
399 if (_IO_old_do_flush (f) == EOF)
400 return EOF;
401 return (unsigned char) ch;
405 attribute_compat_text_section
406 _IO_old_file_sync (FILE *fp)
408 ssize_t delta;
409 int retval = 0;
411 /* char* ptr = cur_ptr(); */
412 if (fp->_IO_write_ptr > fp->_IO_write_base)
413 if (_IO_old_do_flush(fp)) return EOF;
414 delta = fp->_IO_read_ptr - fp->_IO_read_end;
415 if (delta != 0)
417 #ifdef TODO
418 if (_IO_in_backup (fp))
419 delta -= eGptr () - Gbase ();
420 #endif
421 off_t new_pos = _IO_SYSSEEK (fp, delta, 1);
422 if (new_pos != (off_t) EOF)
423 fp->_IO_read_end = fp->_IO_read_ptr;
424 else if (errno == ESPIPE)
425 ; /* Ignore error from unseekable devices. */
426 else
427 retval = EOF;
429 if (retval != EOF)
430 fp->_old_offset = _IO_pos_BAD;
431 /* FIXME: Cleanup - can this be shared? */
432 /* setg(base(), ptr, ptr); */
433 return retval;
436 off64_t
437 attribute_compat_text_section
438 _IO_old_file_seekoff (FILE *fp, off64_t offset, int dir, int mode)
440 off_t result;
441 off64_t delta, new_offset;
442 long count;
443 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
444 offset of the underlying file must be exact. */
445 int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
446 && fp->_IO_write_base == fp->_IO_write_ptr);
448 if (mode == 0)
449 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
451 /* Flush unwritten characters.
452 (This may do an unneeded write if we seek within the buffer.
453 But to be able to switch to reading, we would need to set
454 egptr to pptr. That can't be done in the current design,
455 which assumes file_ptr() is eGptr. Anyway, since we probably
456 end up flushing when we close(), it doesn't make much difference.)
457 FIXME: simulate mem-mapped files. */
459 if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
460 if (_IO_switch_to_get_mode (fp))
461 return EOF;
463 if (fp->_IO_buf_base == NULL)
465 /* It could be that we already have a pushback buffer. */
466 if (fp->_IO_read_base != NULL)
468 _IO_free_backup_buf (fp, fp->_IO_read_base);
469 fp->_flags &= ~_IO_IN_BACKUP;
471 _IO_doallocbuf (fp);
472 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
473 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
476 switch (dir)
478 case _IO_seek_cur:
479 /* Adjust for read-ahead (bytes is buffer). */
480 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
481 if (fp->_old_offset == _IO_pos_BAD)
482 goto dumb;
483 /* Make offset absolute, assuming current pointer is file_ptr(). */
484 offset += fp->_old_offset;
486 dir = _IO_seek_set;
487 break;
488 case _IO_seek_set:
489 break;
490 case _IO_seek_end:
492 struct __stat64_t64 st;
493 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
495 offset += st.st_size;
496 dir = _IO_seek_set;
498 else
499 goto dumb;
502 /* At this point, dir==_IO_seek_set. */
504 /* If we are only interested in the current position we've found it now. */
505 if (mode == 0)
506 return offset;
508 /* If destination is within current buffer, optimize: */
509 if (fp->_old_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
510 && !_IO_in_backup (fp))
512 /* Offset relative to start of main get area. */
513 off_t rel_offset = (offset - fp->_old_offset
514 + (fp->_IO_read_end - fp->_IO_read_base));
515 if (rel_offset >= 0)
517 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
519 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
520 fp->_IO_read_end);
521 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
523 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
524 goto resync;
527 #ifdef TODO
528 /* If we have streammarkers, seek forward by reading ahead. */
529 if (_IO_have_markers (fp))
531 int to_skip = rel_offset
532 - (fp->_IO_read_ptr - fp->_IO_read_base);
533 if (ignore (to_skip) != to_skip)
534 goto dumb;
535 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
536 goto resync;
538 #endif
540 #ifdef TODO
541 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
543 if (!_IO_in_backup (fp))
544 _IO_switch_to_backup_area (fp);
545 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
546 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
547 goto resync;
549 #endif
552 #ifdef TODO
553 _IO_unsave_markers (fp);
554 #endif
556 if (fp->_flags & _IO_NO_READS)
557 goto dumb;
559 /* Try to seek to a block boundary, to improve kernel page management. */
560 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
561 delta = offset - new_offset;
562 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
564 new_offset = offset;
565 delta = 0;
567 result = _IO_SYSSEEK (fp, new_offset, 0);
568 if (result < 0)
569 return EOF;
570 if (delta == 0)
571 count = 0;
572 else
574 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
575 (must_be_exact
576 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
577 if (count < delta)
579 /* We weren't allowed to read, but try to seek the remainder. */
580 offset = count == EOF ? delta : delta-count;
581 dir = _IO_seek_cur;
582 goto dumb;
585 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
586 fp->_IO_buf_base + count);
587 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
588 fp->_old_offset = result + count;
589 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
590 return offset;
591 dumb:
593 _IO_unsave_markers (fp);
594 result = _IO_SYSSEEK (fp, offset, dir);
595 if (result != EOF)
597 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
598 fp->_old_offset = result;
599 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
600 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
602 return result;
604 resync:
605 /* We need to do it since it is possible that the file offset in
606 the kernel may be changed behind our back. It may happen when
607 we fopen a file and then do a fork. One process may access the
608 file and the kernel file offset will be changed. */
609 if (fp->_old_offset >= 0)
610 _IO_SYSSEEK (fp, fp->_old_offset, 0);
612 return offset;
615 ssize_t
616 attribute_compat_text_section
617 _IO_old_file_write (FILE *f, const void *data, ssize_t n)
619 ssize_t to_do = n;
620 while (to_do > 0)
622 ssize_t count = __write (f->_fileno, data, to_do);
623 if (count == EOF)
625 f->_flags |= _IO_ERR_SEEN;
626 break;
628 to_do -= count;
629 data = (void *) ((char *) data + count);
631 n -= to_do;
632 if (f->_old_offset >= 0)
633 f->_old_offset += n;
634 return n;
637 size_t
638 attribute_compat_text_section
639 _IO_old_file_xsputn (FILE *f, const void *data, size_t n)
641 const char *s = (char *) data;
642 size_t to_do = n;
643 int must_flush = 0;
644 size_t count = 0;
646 if (n <= 0)
647 return 0;
648 /* This is an optimized implementation.
649 If the amount to be written straddles a block boundary
650 (or the filebuf is unbuffered), use sys_write directly. */
652 /* First figure out how much space is available in the buffer. */
653 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
655 count = f->_IO_buf_end - f->_IO_write_ptr;
656 if (count >= n)
658 const char *p;
659 for (p = s + n; p > s; )
661 if (*--p == '\n')
663 count = p - s + 1;
664 must_flush = 1;
665 break;
670 else if (f->_IO_write_end > f->_IO_write_ptr)
671 count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
673 /* Then fill the buffer. */
674 if (count > 0)
676 if (count > to_do)
677 count = to_do;
678 if (count > 20)
680 f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
681 s += count;
683 else
685 char *p = f->_IO_write_ptr;
686 int i = (int) count;
687 while (--i >= 0)
688 *p++ = *s++;
689 f->_IO_write_ptr = p;
691 to_do -= count;
693 if (to_do + must_flush > 0)
695 size_t block_size, do_write;
696 /* Next flush the (full) buffer. */
697 if (__overflow (f, EOF) == EOF)
698 return to_do == 0 ? EOF : n - to_do;
700 /* Try to maintain alignment: write a whole number of blocks.
701 dont_write is what gets left over. */
702 block_size = f->_IO_buf_end - f->_IO_buf_base;
703 do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
705 if (do_write)
707 count = old_do_write (f, s, do_write);
708 to_do -= count;
709 if (count < do_write)
710 return n - to_do;
713 /* Now write out the remainder. Normally, this will fit in the
714 buffer, but it's somewhat messier for line-buffered files,
715 so we let _IO_default_xsputn handle the general case. */
716 if (to_do)
717 to_do -= _IO_default_xsputn (f, s+do_write, to_do);
719 return n - to_do;
722 compat_symbol (libc, _IO_old_do_write, _IO_do_write, GLIBC_2_0);
723 compat_symbol (libc, _IO_old_file_attach, _IO_file_attach, GLIBC_2_0);
724 compat_symbol (libc, _IO_old_file_close_it, _IO_file_close_it, GLIBC_2_0);
725 compat_symbol (libc, _IO_old_file_finish, _IO_file_finish, GLIBC_2_0);
726 compat_symbol (libc, _IO_old_file_fopen, _IO_file_fopen, GLIBC_2_0);
727 compat_symbol (libc, _IO_old_file_init, _IO_file_init, GLIBC_2_0);
728 compat_symbol (libc, _IO_old_file_setbuf, _IO_file_setbuf, GLIBC_2_0);
729 compat_symbol (libc, _IO_old_file_sync, _IO_file_sync, GLIBC_2_0);
730 compat_symbol (libc, _IO_old_file_overflow, _IO_file_overflow, GLIBC_2_0);
731 compat_symbol (libc, _IO_old_file_seekoff, _IO_file_seekoff, GLIBC_2_0);
732 compat_symbol (libc, _IO_old_file_underflow, _IO_file_underflow, GLIBC_2_0);
733 compat_symbol (libc, _IO_old_file_write, _IO_file_write, GLIBC_2_0);
734 compat_symbol (libc, _IO_old_file_xsputn, _IO_file_xsputn, GLIBC_2_0);
736 #endif